2010-02-15 315 views
34

我有對象obj這是第三方組件,超時設置爲操作

// this could take more than 30 seconds 
int result = obj.PerformInitTransaction(); 

我不知道里面是什麼發生。 我知道的是,如果需要更長的時間,那就失敗了。

如何設置一個超時機制來執行這個操作,這樣如果需要30秒以上的時間我只需要扔MoreThan30SecondsException

回答

66

你可以在一個單獨的線程中運行的操作,然後把超時的線程上的連接操作:

using System.Threading; 

class Program { 
    static void DoSomething() { 
     try { 
      // your call here... 
      obj.PerformInitTransaction();   
     } catch (ThreadAbortException) { 
      // cleanup code, if needed... 
     } 
    } 

    public static void Main(params string[] args) { 

     Thread t = new Thread(DoSomething); 
     t.Start(); 
     if (!t.Join(TimeSpan.FromSeconds(30))) { 
      t.Abort(); 
      throw new Exception("More than 30 secs."); 
     } 
    } 
} 
+1

@Bomboca:我回滾您的編輯時,'Exception'我要把不應該是'ThreadAbortException',這點是由CLR時,拋出通話到「中止」。 –

+0

對不起,感謝您的輸入:) –

+2

這是一個阻塞呼叫,如果你需要主線程在這個時候做其他事情,這將無法正常工作! – feldeOne

1

你可以看看在一個線程,並在超時調用方法,中止線程,引發異常。此外,在這種情況下,您必須處理ThreadBorted異常。

+0

您對ThreadAbortedException +1正確。 –

0

有一個很好的例子,通用的解決方案使用幫助類here

它使用Action委託來避免前面示例中顯示的線程創建/銷燬。

我希望這會有所幫助。

2

您需要小心中止這樣的操作,特別是因爲它在第三方組件中,您(可能)無法訪問要修改的代碼。

如果您中止操作,那麼您將不會知道您已經將底層類留在了什麼狀態。例如,它可能已獲取鎖,並且您的約會導致該鎖未被釋放。即使您在中止操作後銷燬對象,它也可能已經改變了一些全局的狀態,因此如果不重新啓動,您將無法可靠地創建新實例。

6

如果您不希望阻止您可以使用主線程System.Threading.Timer

private Thread _thread; 

void Main(string[] args) 
{ 
    _thread = new ThreadStart(ThreadEntry); 
    _thread.Start(); 
    Timer timer = new Timer(Timeout,null,30000,Timeout.Infinite); 
} 


void ThreadEntry() 
{ 
    int result = obj.PerformInitTransaction(); 
} 

void TimeOut(object state) 
{ 
    // Abort the thread - see the comments 
    _thread.Abort(); 

    throw new ItTimedOutException(); 
} 

喬恩斯基特有停止線比中止的力度較小的方式(Shutting Down Worker Threads Gracefully)。

但是,由於您無法控制操作PerformInitTransaction()正在執行,因此當Abort失敗並使對象處於無效狀態時,您可以做的事情不多。如上所述,如果您可以清理任何中止PerformInitTransaction中止的事件,則可以通過捕獲ThreadAbortException來完成此操作,但由於它是第三方調用,這意味着要猜測您已將方法留在的狀態。

PerformInitTransaction應該確實是提供暫停的那個。

10

更簡單地使用Task.Wait(TimeSpan)

using System.Threading.Tasks; 

var task = Task.Run(() => obj.PerformInitTransaction()); 
if (task.Wait(TimeSpan.FromSeconds(30))) 
    return task.Result; 
else 
    throw new Exception("Timed out"); 
+0

這是非常簡單的,自.NET 4.0起可用。 –

+0

這不會殺死線程 –