2010-10-27 44 views
0

如果有兩個線程作爲生產者/消費者,那麼有下面一行來防止死鎖是個好主意。我所知道的活鎖,但假設他們做了很多工作,調用此wait()方法之前:線程切換和死鎖預防問題

// member variable 
object _syncLock = new object(); 

void Wait() 
{ 
    lock (_syncLock) 
     { 
     Monitor.Pulse(_syncLock); 
     Monitor.Wait(_syncLock); 
     } 
} 

這是不可能的兩個線程處於等待狀態。

+0

通過擴大鎖定範圍解決了問題,並且移除了Wait()和Pulse()。我從裏德那裏學到的是,爲什麼我只用兩條線索和已知的生產者/消費者模式來解決這個問題呢?所以,重新設計的時候在看大圖。關鍵是在Visual Studio中尋找代碼時,代碼行比CPU週期更有意義,因此如果事實上代碼行不能比較上下文切換,那麼很容易使鎖定時間最小化。 – Xaqron 2010-10-28 03:17:16

回答

2

這似乎過於複雜。首先正確處理你的鎖定,並避免這個問題。如果你只有兩個線程,並且他們試圖獲得相同的單一鎖(正確),你就不應該有死鎖。死鎖意味着這裏還有其他事情發生。這就是說,如果您可以選擇通過.NET 4(或.NET 3.5上的Rx Extensions)使用TPL,則可以考慮使用BlockingCollection<T>代替。它非常適合在生產者/消費者場景中使用,並以無鎖方式工作。

+0

當生產或消費的速度非常高時發生死鎖。例如,當生產者填充隊列並進入睡眠狀態時,隊列變爲空,並且兩個線程都保持等待,或者如果消費者檢查並且在他進入睡眠之前沒有什麼消耗,那麼生產者填充隊列並且都進入睡眠狀態。由於性能問題,我不會鎖定整個產品或消費報表。阻礙收集對於單一的生產者/消費者而言並不是好事,因爲性能是重要的。 – Xaqron 2010-10-27 17:13:03

+0

@ Xaqron:您是否真的評估過引入鎖會對應用程序的性能產生顯着影響?這似乎是不成熟的優化,導致更復雜的設計。 – BrokenGlass 2010-10-27 18:51:12

+0

@Xaquon:BlockingCollection 實際上恰恰相反 - 它對於單一生產者,單一消費者而言是非常優化的。即使鎖定很小,它可能比在標準集合上使用鎖定要快得多。 – 2010-10-27 19:49:03

1

如果你的目的是建立生產者 - 消費者模式的配對變種則序列是PulsePulse爲消費者之前Wait爲生產者和Wait之前。您可以參考Joe Duffy's article on this中的圖5。 Howerver,請記住,由於他的實施在Enqueue方法中執行無條件Wait,所以生產者和消費者之間會發生乒乓效應。在他的實施中,隊列中每個生產者只能有一個項目。所以,如果這是你的意圖,那麼這是你的票。否則,您可以按照原樣對其進行調整,並將中的某些條件應用於Enqueue方法中的Wait,以使其表現得更像真正的FIFO緩衝區。

但是,像裏德一樣,我懷疑爲什麼BlockingCollection無法使用。此集合應該非常高效,因爲它爲AddTake方法使用了無鎖策略。當然,就像我上面提到的那樣,如果你真的想要配對變體,那麼這個集合將不會滿足你的要求,你將不得不使用Joe Duffy作爲起點。

只需記住將等待前使用while循環而不是if檢查。 Monitor.Wait只是等待鎖定狀態的改變,而不是更多,因此您必須重新檢查等待條件。

+0

+1生產者/消費者等待/脈衝訂單。 BlockingCollection對我來說不夠靈活,因爲我在不同的消費點監督生產者。只要有空間存放另一件物品,阻止收藏品就會發出衝擊,同時我讓他爲我的場景休息。 – Xaqron 2010-10-28 03:23:49

+0

@Xaqron:然後你必須推出你自己的阻塞隊列。 – 2010-10-28 15:47:27