2011-05-09 16 views
10

下面是一個說明我的問題的方法'SomeMethod'的類。如何解鎖已在AutoResetEvent對象上調用WaitOne方法的線程?

class SomeClass 
{ 
    AutoResetEvent theEvent = new AutoResetEvent(false); 
    // more member declarations 

    public void SomeMethod() 
    { 
     // some code 
     theEvent.WaitOne(); 
     // more code 
    } 
} 

該方法的設計是線程安全的,將在不同的線程中調用。現在我的問題是如何在任何時間點解鎖所有在'theEvent'對象上調用'WaitOne'方法的線程?這種要求經常出現在我的設計中,因爲我需要能夠正常停止並啓動我的多線程程序。在我看來,啓動一個多線程程序相當簡單,但要停止一個程序很困難。

這是我迄今爲止試過的顯然有效的東西。但這是標準方法嗎?

public void UnblockAll() 
{ 
    do 
    { 
     theEvent.Set(); 
    } while (theEvent.WaitOne(0)); 
} 

'UnblockAll'方法是'SomeClass'類的成員。此處使用的技術基於WaitOne method的MSDN文檔。我引用以下文檔的相關部分:

如果毫秒超時爲零,則該方法不會阻塞。它測試等待句柄的狀態並立即返回。

在do..while循環中,我調用Set method。這釋放了由於對WaitOne方法的調用而被阻塞的單個線程(在'SomeMethod'方法中編碼)。接下來,我測試'theEvent'對象的狀態,以瞭解它是否有信號。這個測試是通過調用WaitOne方法的超載版本來完成的,該方法需要超時參數。我在調用WaitOne方法時使用的參數爲零,根據文檔結果,調用立即返回一個布爾值。如果返回值爲true,那麼處於信號狀態的'theEvent'對象。如果在'SomeMethod'方法中調用'WaitOne'方法時至少有一個線程被阻塞,那麼對'Set'方法的調用(在'UnblockAll'方法中編碼)將會解除阻塞。因此,在'UnblockAll'方法中do..while語句結束時對'WaitOne'方法的調用將返回false。只有在沒有線程被阻塞的情況下,返回值才爲真。

上述推理是否正確,如果是對的,該技術是解決我的問題的標準方法嗎?我正在嘗試主要在.net compact-framework 2.0平臺上使用該解決方案。

+1

題外話 - 你不能調用變量 - 「事件」 – Maxim 2011-05-09 17:14:42

+1

聽起來像你想的ManualResetEvent來代替。這樣,即使您有多個偵聽器,它也會保持設置。 – 2011-05-09 20:41:12

+0

@Maxim。糾正了代碼中的語法錯誤.. – ghd 2011-05-10 04:16:30

回答

3

你的程序可能大部分時間都在工作,但我不認爲有任何保證,其中一個等待線程會在你的關閉循環設置它的時間和關閉循環檢查的時間之間重置事件它再次。

我發現AutoResetEvent和ManualResetEvent類對於非常簡單的場景非常適用。任何時候對這些要求都有些奇怪,我會很快轉向更靈活的Wait And Pulse pattern

如果你不需要任何清理,你可以讓你的工作線程後臺線程,然後他們就會停止時,主線程退出。

您可能還可以定義第二個ManualResetEvent,稱爲stopRequest並等待來自任一事件的信號。但是,這可能不是緊湊框架支持的。

+0

在.Net精簡框架2.0平臺中沒有Wait-Pulse方法可用:-( – ghd 2011-05-10 04:58:53

+0

整個程序被組織成一組協作的「組件」。一些組件被使用我覺得除非我提供了一種手段來正常關閉一個組件,而不會對其他組件產生不利影響,否則我的設計並不完整,因此使得線程的背景是我的最後一個選擇 – ghd 2011-05-10 05:11:53

+0

我一定會選擇使用第二個ManualResetEvent一個嘗試.. – ghd 2011-05-10 05:13:06

1

thread abort是否適合您的框架?

+0

nope。它不適用於緊湊框架2.0平臺 – ghd 2011-05-10 05:01:37

10

您有三種可行的選擇。每個人都有自己的優點和缺點。選擇最適合您的具體情況的那個。

選項1 - 調查WaitHandle

而不是做一個無限制的阻塞調用使用一個超時,並且如果還沒有給出關閉請求,則恢復該塊。

public void SomeMethod() 
{ 
    while (!yourEvent.WaitOne(POLLING_INTERVAL)) 
    { 
    if (IsShutdownRequested()) 
    { 
     // Add code to end gracefully here. 
    } 
    } 
    // Your event was signaled so now we can proceed. 
} 

選項2 - 使用單獨的WaitHandle請求關機

public void SomeMethod() 
{ 
    WaitHandle[] handles = new WaitHandle[] { yourEvent, shutdownEvent }; 
    if (WaitHandle.WaitAny(handles) == 1) 
    { 
    // Add code to end gracefully here. 
    } 
    // Your event was signaled so now we can proceed. 
} 

選項3 - 使用Thread.Interrupt

不要Thread.Abort混淆。中止一個線程絕對是不安全的,但是中斷線程是完全不同的。 Thread.Interrupt會「捅」內建堵在BCL包括Thread.JoinWaitHandle.WaitOneThread.Sleep使用電話等

+0

+1提到WaitAny - 我會試一試! – ghd 2011-05-10 05:30:02

+0

.Net緊湊框架2.0沒有WaitHandle類中的WaitAny方法: - ( – ghd 2011-05-10 06:52:46

+1

太糟糕了,順便說一下,我忘了提及另一個選項,我編輯了我的答案呃。 – 2011-05-10 14:03:55

相關問題