實現一個雙緩衝佇列
阿新 • • 發佈:2019-02-02
在生產者-消費者模式中,我們常常會使用到佇列,這個佇列在多個執行緒共享訪問時存在互斥和競爭操作, 意味著每次訪問都要加鎖。如何更好的如何減少鎖競爭次數呢 ?今天要介紹的雙緩衝佇列就是個不錯的選擇。
雙緩衝佇列就是衝著同步/互斥的開銷來的。我們知道,在多個執行緒併發訪問同一個資源的時候,需要特別注意執行緒的同步問題。稍稍不注意,噢貨,程式結果不正確了。
原理
直接上圖:
鎖
在雙緩衝佇列中,鎖除了起到保護資料安全的作用來,還要承擔執行緒排程的任務。
- 雙佇列交換位置和任務入佇列都需要對當前佇列進行操作,因此,他們是互斥的操作。
- 消費操作放在單獨的執行緒中,在沒有任務進來時,需要將執行緒置為等待狀態。
使用兩個訊號量,來排程入列隊和交換佇列的操作。同時,我們還需要一個訊號量,在沒有任務入佇列時,阻塞整個消費執行緒。
主要使用 AutoResetEvent,ManualResetEvent,它們的具體使用可以看一下園子裡的文章:
http://www.cnblogs.com/springyangwc/archive/2011/10/12/2208991.html
- AutoResetEvent.WaitOne()每次只允許一個執行緒進入,當某個執行緒得到訊號後,AutoResetEvent會自動又將訊號置為不傳送狀態,則其他呼叫WaitOne的執行緒只有繼續等待,也就是說AutoResetEvent一次只喚醒一個執行緒;
- ManualResetEvent則可以喚醒多個執行緒,因為當某個執行緒呼叫了ManualResetEvent.Set()方法後,其他呼叫WaitOne的執行緒獲得訊號得以繼續執行,而ManualResetEvent不會自動將訊號置為不傳送;
- 也就是說,除非手工呼叫了ManualResetEvent.Reset()方法,則ManualResetEvent將一直保持有訊號狀態,ManualResetEvent也就可以同時喚醒多個執行緒繼續執行。
實現
我以一個簡單的示例來演示整個過程。
在生產執行緒中,入佇列一些字串;使用消費執行緒,把這些字串和它所在佇列編號打印出來:
看一下執行效果:
可以看到,在消費執行緒中,佇列交換使用。
下一篇,我們來實現一個對雙緩衝佇列的封裝。