2011-07-08 32 views
3

我有一個應用程序在隊列中使用AutoResetEvent(WaitOne/Set)來處理消息。我注意到,當我終止Visual Studio的一個調試會話(Shift + F5)時,應用程序的原始進程掛起(但並非總是)。我手動將調試器重新連接到進程,並發現它在WaitHandle.WaitOne上存在單線程。由於WaitOne狀態下的AutoResetEvent信號導致應用程序終止後,線程仍然存在

所以我的問題是,終止可能處於WaitOne狀態的線程的正確方法是什麼?

想到的第一個答案是傾聽應用程序退出事件並在那裏做Set,但我不確定在這些調試會話之後是否可靠地調用了此事件,或者是否有更標準的實踐我不知道。

而且,作爲第二個問題,您是否會以「生產」模式運行的應用程序處理這個問題?

+0

嗯,你手上有一個討厭的問題。終止調試會話是使用Windows中最大的槍TerminateProcess()完成的。 Taskmgr.exe中使用的同類槍。只有一種可能的方式是,這不會終止進程,內核線程繁忙併且不能完成I/O請求。這絕對不是一個AutoResetEvent。沒有意義。 –

+0

@Hans - 一旦連接調試器,我在調用堆棧中看到的WaitHandle不是信號的等待句柄,而是內核I/O任務的不同等待句柄?在這項任務中唯一的I/O是一些日誌記錄,這真的很簡單(只是每隔一段時間手動觸發一次,而不是以任何頻率發生) – Matt

+0

我所知道的是,你所描述的並不會使感。因此,如果沒有任何文檔,我會立即假定描述是錯誤的。發佈堆棧跟蹤與非託管調試和Microsoft符號服務器啓用。 –

回答

4

有一個簡單的方法來做到這一點(不是一個解決方法)

首先,您需要設置將火的時候,您的應用程序會死

// somewhere with global scope. On a singleton or in program class maybe 
// this is set when you want to terminate your application 
private static ManualResetEvent ExitWaitHandle = new ManualResetEvent(false); 

一個事件,這是怎麼了在其他地方使用它

// the event you want to check but it's blocking your application termination 
private static AutoResetEvent yourEvent = new AutoResetEvent(true); 

// the method where you have the problem 
private static void FooAsync() 
{ 
    try 
    { 
     WaitHandle.WaitAny(new WaitHandle[]{yourEvent, ExitWaitHandle}); 
     Checkpoint(); 

     // other stuff here 

     // check if thread must die 
     Checkpoint(); 
    } 
    catch(ApplicationTerminatingException) 
    { 
     // thread must die, do cleanup and finalization stuff here 
    } 
    catch(Exception) 
    { 
     // holy cow! what should we do? 
    } 
} 

private void CheckPoint() 
{ 
    // fast check if the exit handle is set 
    if(ExitWaitHandle.WaitOne(0)) 
    { 
     throw new ApplicationTerminatingException(); // custom exception 
    } 
} 

唯一的開銷是,「一些」代碼後,你需要設置一個檢查點,以中止你的線程。希望這是你正在尋找的。

+1

這是一個非常有趣的答案。我明天會嘗試這個第一件事,並讓你知道它是如何發生的。謝謝。 – Matt

+0

我現在又看到了這一點,我的代碼在我面前,並有幾個問題。 1)我認爲你的'全局'範圍ExitWaitHandle應該公開嗎? 2)這裏的基本思想是在關機過程中通過ExitWaitHandle打開信號的「門」,從而釋放任何等待句柄並允許它們自行處理? – Matt

+0

@Matt是的,你打開「門」!至於事件,它不應該是公開的,而是可以從所有需要監聽應用程序終止事件的類訪問。您可以實現觀察者模式,其中用戶是線程。只是一點點代碼納粹評論:我喜歡'內部'關鍵字而不是'公共'這樣的東西。 – Odys

1

一種解決方法是使用Thread.IsBackground屬性將線程設置爲後臺線程。在線程上設置時,線程不會停止退出進程。

但是,線程可能隨時中斷,通常會導致未定義的行爲,具體取決於您的線程正在做什麼。以我愚蠢的觀點終止線索的最好方法是指示線程退出,例如,通過設置退出標誌並設置WaitHandle並將其喚醒然後Join進入線程。

+0

線程實際上是通過.NET 4 Task對象處理的。我想我可以做一些手動線程... – Matt

相關問題