2015-04-28 126 views
1

我在Win32設備中有一個C++程序。代碼具有函數X,該函數應該阻止對X的其他調用。這很簡單,我可以使用一個互斥體來實現這一點。鎖定多個線程

但是,函數X會創建並啓動一個線程Y,該線程將在X完成後監視事物。我需要確保X不能再次運行,直到Y確信一切正常完成。

據我所知,互斥鎖只能在同一個線程上獲取和釋放。我想要做的是將互斥鎖的'鎖定'從X移交給Y.

如果根據實際發生的情況更容易地描述這一點,那麼X在那裏打印一些東西,Y是否要檢查打印作業是否完成而紙張用完?一旦Y確信工作已經完成並且紙張沒有用完,那麼它可以讓X打印其他東西。我們要X到儘快完成,以便該設備可以與其他的工作吧(這通常不涉及印刷,因此不應承擔了,而在打印機完成打印。)

所以...有沒有一個標準的交叉線程鎖定模式,將做我想做的事情?

我不能使用boost或任何其他第三方庫,只能使用Windows內置操作。

+0

也許一個計時器而不是一個線程? –

+0

線程Y將一直運行,直到打印作業完成,並且可以包括通知用戶紙張已用完並等待新紙張可用,即可能需要很長時間並且不足以讓計時器幫助。 – ColinM

+1

線程X和Y的[同步障礙](https://msdn.microsoft.com/zh-cn/library/windows/desktop/ms686360.aspx#synchronization_barrier_functions)可用於實現此要求。 – IInspectable

回答

2

夠簡單關注場景。你所需要做的就是用auto-reset event替換互斥量,最初發信號。

的自動重置事件可以以同樣的方式被用作一個互斥體(受到一些限制性條款,見下文),但可以通過任何線程發佈:

  • 事件開始時發出信號(「無主「)。
  • 要輸入函數X,請等待事件。只有一個線程將被允許進入,並且該事件將被自動清除。
  • 函數X啓動線程Y,然後退出而沒有表示事件。
  • 此時沒有線程可以輸入函數X,甚至沒有進行上一次調用的線程。
  • 當線程Y完成其工作時,它表示該事件。這將允許只有一個線程進入功能X.

有互斥對象和事件對象之間有一些差別,你應該知道的:

  • 與互斥,自動復位事件不允許由同一個線程遞歸輸入。因此,如果函數X自行調用,則需要稍微重新排列代碼,以便獲取鎖定發生在遞歸之外。

  • 與互斥量不同,如果「擁有」事件的線程意外退出,API不會生成錯誤。因此,如果Y在沒有通知事件的情況下退出,應用程序將陷入僵局。如果這是一個問題,您需要自己監控線程Y的狀態。 (當然,同樣的道理也適用於線程調用X,如果它推出Y.之前退出)

0

我會扭轉線程的順序:

  • 線程y將會互斥
  • 線程開始出現Y線X做印刷
    • 線程X做它打印和返回
    • 線Y等待其狀態並監視打印
  • 線程Y釋放互斥鎖

這種方式可以讓你在同一個線程中鎖定和釋放互斥鎖。此外,您獲得的關注一個更好的分離:

  • X只與印刷的交易,甚至不知道的Y
  • Y被同步,並正確打印結束
+0

我喜歡這個想法,雖然它是一個雙線程解決方案,而不是創建單個線程的函數。所以在這裏啓動線程Y的代碼將不得不等待,直到X完成,然後我們仍然必須確保在我們等待的時候第二個Y不能啓動。 但我會更多地考慮它,因爲我喜歡關注的分離。 – ColinM

+0

@ColinM:如果你認爲你只需要一個新線程,Y可以是一個在調用線程中運行的函數。我的解決方案只是反轉顯示器調用打印機,而不是相反。 –

0

我標誌着哈利·約翰斯頓的答案接受,因爲它聽起來像它會做的工作精,似乎是一個很好的通用解我甚至可以使用它。

我現在所做的是用兩個臨界區對象替換單個互斥體,我們稱它們爲CSx和CSy。進入X取決於輸入CSx。一旦完成,X也進入CSy。然後立即離開CSy,這是因爲當線程Y啓動時,它將在其生命期內進入CSy。 X進入CSy(並立即離開)的唯一原因是因爲這就是它知道線程Y不是從以前的調用運行到X.

這與上面的Erik的註釋類似,但不是跟蹤單個線程處理它允許多個X和Y排隊。

這裏的風險是線程Y在函數X離開CSx之前可能不會進入CSy,因此有一個範圍讓另一個X首先進入,儘管設備的環境和它在做什麼意味着它不會實際上發生。

儘管如此,Harry的解決方案還是具有單一鎖定對象的優點,以及它帶來的簡單和優雅。

+0

接受一個答案沒有upvoting它看起來是錯誤的。 – IInspectable