2016-01-13 98 views
4

我目前正在使用一個使用來自不同部門的程序集的軟件。
我把這個組件的方法是這樣的:取消命令的執行時間太長

using (var connection = (IConnection) Factory.GetObject(typeof (IConnection))) 

使用完全正常工作的代碼。但是在最後幾分鐘裏,當我嘗試啓動它時,似乎我的程序沒有做任何事情。在調試過程中按下暫停,表明它在上面的線上「卡住」了。
我的猜測是他們只是在做一些維護或某些事情,但這不是重點。
所以我雖然很高興告訴用戶如果程序無法啓動,出了什麼問題。簡單的東西就像

MessageBox.Show("Could not connect", "Connection Error"); 

然後關閉程序。我的問題是:
如何在一段時間後終止命令的執行並跳到別的地方?
我的猜測是將它移動到一個單獨的線程,然後讓調用線程休眠幾秒鐘,之後它會處理額外的線程,如果它尚未完成。但是,這似乎真的對我來說很髒,這是一個更好的方法。

+0

如果你的'IConnection'是'SqlConnection',你可以使用它提供的默認連接超時。 – 2016-01-13 10:36:24

+0

@Kilanny雖然使用非常相似,但它不是SqlConnection,沒有人似乎打擾實現超時。 – Wilsu

+0

否則使用'Timer'來檢查執行,當超時時它應該終止作業 – 2016-01-13 10:44:02

回答

4

你的問題可以分成兩個部分:

  1. 如何終止命令的執行?

唯一的方法是中止線程。 但是不要這樣做。沒有保證和安全的方式。有像Thread.Interrupt和Thread.Abort這樣的方法可以喚醒線程。但是,只有當線程處於WaitSleepJoin狀態並且掛起在託管代碼中時,它們纔會工作。

看起來像你已經知道它。但是再一次,如果程序集中的東西無限地掛起了代碼的執行,那麼線程可能「不見了」。所以你說得對,該程序應該關閉。

  1. ...跳到其他地方?

好的方法是使用TPL和異步模型。 下面是一個擴展方法來包裝任何任務並在超時後到期。

public static async Task TimeoutAfter(this Task task, int millisecondsTimeout) 
{ 
    if (task == await Task.WhenAny(task, Task.Delay(millisecondsTimeout))) 
     await task; 
    else 
     throw new TimeoutException(); 
} 

然後用它

try 
{ 
    using (var result = await Task.Run(() => (IConnection)Factory.GetObject(typeof(IConnection))).TimeoutAfter(1000)) 
    { 
     ... 
    } 
} 
catch (TimeoutException ex) 
{ 
    //timeout 
} 

Here你可以找到更多的信息,這樣做沒有額外的庫或擴展方法的

+0

詳細的答案給予更詳細的說明。我喜歡它。謝謝。 – Wilsu

2

如上所述,如果未實現本機超時,則最簡單的方法是單獨加載一個線程。雖然這聽起來像它會非常髒,這是因爲(使用Rx)的簡單:

Task<IConnection> connectionTask = Observable.Start(() => Factory.GetObject(typeof (IConnection)), Scheduler.Default).Timeout(TimeSpan.FromSeconds(20)).ToTask()); 
using (var connection = connectionTask.Result) 
{ 
    ... 
} 

你可以調整Scheduler,如果你不希望它的線程池運行。如果Factory.GetObject的呼叫時間超過20秒,它將拋出一個TimeoutException

+0

同樣的想法,但很多順暢。非常感謝。我用'try-catch'包圍它,但是當我嘗試調試時,它說它永遠不會達到我放在catch中的斷點。看起來很奇怪,我明天再看看這個。 – Wilsu

3

一個簡單的方法:

using (var task = new Task<IConnection>(() => Factory.GetObject(typeof(IConnection)))) 
{ 
    task.Start(); 

    if(!task.Wait(timeoutMilliseconds)) 
    { 
     throw new TimeoutException(); 
    } 

    IConnection result = task.Result; 
} 

Task.Wait做什麼你想要的,因爲如果它可以拋出異常原來假(任務沒有及時完成。)

,如果你有一個動作不返回的東西這是更簡單:

if (!Task.Run(action).Wait(timeoutMilliseconds)) 
{ 
    throw new TimeoutException(); 
} 

哪裏action一些Action或λ。