2015-09-16 72 views
0

我有一個非託管類正在爲子Win32窗口運行消息循環。當程序關閉時,它啓動託管類的終結器,該託管類包含對此類的非託管引用。由於另一個線程依賴於此類,因此我需要終結器等待消息循環線程完成一個循環並退出並終止。但是,對於GC終結器線程來說,超時循環顯然需要太長時間,否則主線程會終止銷燬整個進程。如何確保線程在終結器完成之前未終止

有沒有辦法告訴GC不要超時終結器的線程? I.E. - 我需要終結器線程在終結器中阻塞一會兒,這樣它可以完成終止消息循環線程,然後釋放非託管資源。

這裏是我的終結,所以你得到了什麼事情的想法:

PONms::NestedWin32:: 
!NestedWin32() 
{ 

    if (msgLoop->IsAlive) 
    { 
     winProcess->EndThread(); // blocks and waits for message loop thread to terminate 
           // and GC apparently doesn't like this causeing the 
           // entire process to terminate here. 
    } 
    if (childHandle != nullptr) 
    { 
     DestroyWindowCore(childHandle); 
    } 
    if (winProcess != nullptr) 
    { 
     delete winProcess; // memory leak due to resource not being released 
    } 
} 

我想我去有關這個錯誤的方式,只是希望該代碼可正常使用,並終結來完成。

下面是一個簡單的方法,我用它來輪詢其他線程,看它是否已終止:

void PONms::NestedWin32UM:: 
EndThread() 
{ 
    int timeOut = 5000; 
    threadContinue = false; 
    SendNotifyMessage(childWin, WM_CLOSE, 0, 0); 
    while (threadActive && timeOut > 0) 
    { 
     POCPP::Threading::SleepThreadOne(); 
     timeOut--; 
    } 
} 

回答

2
int timeOut = 5000; 

即與終結器線程超時默認CLR政策相當激烈的錯配。你有2秒鐘完成工作。現代處理器大約有100億條指令。我們看不到SleepThreadOne()做了什麼,但睡眠(1)不會在1毫秒內休眠。默認的睡眠粒度是15.625毫秒,所以你最終會等待長達78秒。

從技術上講,您可以通過自定義託管CLR,ICLRPolicyManager::SetTimeout() method,OPR_FinalizerRun設置來延長超時。但是,實際上,如果你不能用100億條指令破解它,那麼擴展它不太可能帶來救濟。

調試這並不那麼簡單,那2秒就匆匆結束了。看看結構修復。不要使用bool來同步代碼,使用事件(CreateEvent winapi函數)。 WaitForSingleObject()有一個超時等待它被設置。最多使用1000毫秒,以便讓終結器線程有足夠的呼吸空間。並且要求消息循環退出,WM_CLOSE太友善了。代碼易於通過「保存更改?」做出響應消息框,這是一個保證失敗。使用PostQuitMessage()。或者根本不打擾,程序應該通過用戶界面終止,你似乎需要以另一種方式拉動地毯。 「你最終會等待長達78秒。」

+0

「 - 唉,是的,我忘了那個。沒有任何情況下,在正常情況下需要很長時間才能釋放 - 但我會縮短現在記得睡眠解決時間的時間間隔。 「PostQuitMessage()」PQM不採用我可以告訴的HWND句柄,調用它的線程不是擁有線程。這個窗口只是WPF中的一個DX主機而沒有使用HwndHost,它不會有任何「保存更改」對話框或任何東西。這是一個假裝成WPF控件的窗口。 – ThisHandleNotInUse

+0

我似乎已經通過訂閱「Application.Exit」事件並在那裏處理銷燬來解決我的問題。我想我只會爲其他情況實施手動銷燬。 – ThisHandleNotInUse