2011-06-26 178 views
4

我們的(Windows本地C++)應用程序由線程對象和管理器組成。它寫得非常好,設計中可以看到管理器對象控制着他們的爪牙的生命週期。各種物體發送和接收事件;有些事件來自Windows,有些是自制的。受控應用程序關閉策略

一般情況下,我們有,所以我們使用使用Win32臨界區,信號燈等的手卷同步技術是非常知曉線程的互操作性。但是,偶爾我們會因爲事件處理程序重入等原因而在關閉期間遭受線程死鎖。

現在我想知道是否有一個像樣的應用程序關閉策略,可以讓我們更容易開發 - 就像每個對象從中央控制器註冊關閉事件並相應地更改其執行行爲?這是太天真還是脆弱?

,我寧願沒有規定重寫整個應用程序使用微軟的並行模式庫或類似的策略。 ;-)

感謝。

編輯:

我想我要求的方法在複雜的應用程序中許多線程和事件被解僱所有的時間控制對象的生命週期。 Giovanni的建議很明顯(我們自己動手滾動),但我相信必須有各種現成的策略或框架,才能以正確的順序乾淨地關閉活動對象。例如,如果您想將您的C++應用程序基於IoC範例,則可以使用PocoCapsule而不是嘗試開發自己的容器。在應用程序中是否有類似的控制對象生命週期?

+0

爲什麼事件處理程序(已使用)/(尤其是問題)在關機時(而不是在其他時間)? – Mankarse

+1

我只是想寫一個答案,但我意識到這個問題是無法解析的,因爲它如果你遇到了死鎖,那麼這不是一個設計問題,而是一個實現問題(當然你現在的設計可能會使一個正確的實現變得不可能)任何修復死鎖的設計都是一個改進。 – Mankarse

+0

@mankarse因爲我們的關閉策略在某些地方不夠強大,以防止在事件被調度和處理的過程中出現死鎖,當然這些都是簡單的錯誤,並且當發現時,這些錯誤是固定的。 – dripfeed

回答

1

一個可能的一般策略是發送「我在關停」事件,每一位經理,這將導致經理人做的三兩件事之一(具體上運行的事件處理程序是多長時間,多少您希望啓動關機的用戶和應用程序實際退出之間的延遲)。

1)停止接受新事件,並運行「我正在關閉」事件之前收到的所有事件的處理程序。爲避免死鎖,您可能需要接受對完成其他事件處理程序至關重要的事件。這些可以通過事件中的標誌或事件的類型來指示(例如)。如果你有這樣的事件,那麼你也應該考慮重構你的代碼,以便這些操作不是通過事件處理程序執行的(因爲依賴事件在普通操作中也容易出現死鎖。)

2)停止接受新事件,丟棄處理程序當前正在運行的事件後收到的所有事件。關於依賴事件的類似評論也適用於這種情況。

3)中斷當前正在運行的事件(具有類似於boost::thread::interrupt()的函數),並運行沒有進一步的事件。這要求您的處理程序代碼是異常安全的(如果您關心資源泄漏,它應該已經是這樣了),並且要以相當規律的時間間隔輸入中斷點,但這會導致最小延遲。

當然,您可以將這三種策略混合在一起,具體取決於每個管理員的特定延遲和數據損壞要求。

1

作爲一般的方法,使用原子布爾值,表明「我是關停」,那麼每一個線程檢查獲取的每個鎖,每次處理事件之前這個布爾等不能,除非你給我們提供一個更詳細的解答一個更詳細的問題。

3

這似乎是一個更普遍問題的特例:「我如何避免多線程應用程序中的死鎖?」

答案就是,一如既往:確保任何時候你的線程必須一次獲得多個鎖,它們都以相同的順序獲得鎖,並確保所有線程釋放它們鎖定在有限的時間內。此規則在關機時與其他時間一樣適用。沒有什麼是不夠的;沒有更多是必要的。 (請參閱here進行相關討論)

至於如何最好地做到這一點......最好的方法(如果可能的話)是儘可能簡化您的程序,並避免每次只能持有一個以上的鎖如果你可以幫助它。

如果您絕對要求必須一次持有多個鎖,您必須驗證您的程序以確保每個擁有多個鎖的線程以相同的順序鎖定它們。像helgrind or Intel thread checker這樣的程序可以幫助解決這個問題,但是它通常歸結爲簡單地看代碼,直到你證明自己滿足了這個約束。此外,如果您能夠輕鬆地重現死鎖,則可以檢查(使用調試器)每個死鎖線程的堆棧跟蹤,這將顯示死鎖線程永遠被阻塞的位置,並且利用該信息可以啓動找出你的代碼中鎖定順序不一致的地方。是的,這是一個主要的痛苦,但我認爲沒有任何好的方法(除了避免同時持有多個鎖)。 :(

+0

+1鎖定策略鏈接。 – dripfeed