執行緒同步的情景之三

2021-09-22 09:50:52 字數 2537 閱讀 6091

在情景

一、情景二中,我分別介紹了當多執行緒遇到 「資源爭用」、「限量使用」 情形時的解決方案,本篇是本系列的最後一種情形,會介紹幾種用於解決執行緒通訊的方案。

情景三:我讓你動,你才能動!

大錘:「老闆,拿這個手機讓我看看」。

大錘:「這是手機嗎??? 分別就只是乙個殼子」。

老闆:「呀,這可能是生產上出了問題,我給你換乙個!」

大錘:「老闆,你這是當我是傻子呢?還是傻子呢?還是傻子呢? 這回給我的手機怎麼沒有電源啊!我要怎麼開機啊!」

萬萬沒想到,經過千挑萬選,最終還是找到了乙個配件完整的手機。

老闆回去後發現了原因是:生產和上線銷售兩個環節沒有搭配好,當生產的環節還沒有結束時,就把中間產物拿去銷售了。

解決辦法:所有動作不能擅自執行,必須服從命令,當生產環節完成時會通知上線環節,然後才被允許拿到市場上去銷售。

問題抽象:當某個操作的執行必須依賴於另乙個操作的完成時,需要有個機制來保證這種先後關係。

執行緒通訊方案:manualreseteventslim、manualresetevent、autoresetevent

方案特性:提供執行緒通知的能力,沒有接到通知前,執行緒必須等待,有先後順序。

各方案間的區別

manualresetevent 和 autoresetevent 都繼承自 eventwaithandle 並最終與 mutex 和 semaphore 一樣擁有共同的祖宗: waithandle。在前面幾篇中我有講過 waithandle 是乙個抽象類,包裝了 windows 作業系統的核心物件控制代碼。

manualresetevent: 中文理解就是手動重置事件(這裡的事件並不是我們通常意義中按鈕的那種事件,更多的應該理解為乙個通告)。所有事件的初始狀態都為 「不可用」,任何在等待該事件的執行緒都將一直等待下去。只有當通過 set 方法釋放了乙個訊號後,等待該事件的執行緒才被允許執行所需的操作。如果不手動重置,那麼狀態一直為 「可用」,任何等待該事件的執行緒可以繼續執行操作。只有當呼叫 reset 方法後,狀態才會變為 「不可用」。通過 waitone 來請求狀態,從而決定是否執行操作。

這個特點,有點類似紅綠燈,當綠燈亮起,所有機動車都被允許通過,直到再次變成紅燈。

與 mutex 不同的是,reset 和 set 操作可以由不同的執行緒發起。如:

manualresetevent s = new manualresetevent(false); 

task.factory.startnew(() =>);

task.factory.startnew(() =>);

task.factory.startnew(() =>);

優點:提供執行緒間通訊的能力,可以跨程序使用。

缺點:速度慢於使用者模式、混合模式構造,稍快於 mutex。

autoresetevent: 顧名思義,就是自動重置事件。如果 manulresetevent 相當於紅綠燈,那 autoresetevent 就類似高速入口的閘機,杆抬起一次,通過一輛車。第二輛車要重新等待杆抬起。當呼叫 set 後,狀態變成 「可用」,但只要一執行 waitone 請求狀態後,狀態即可變成 「不可用」(這個過程不需要 reset 方法的參與)。

優點:提供執行緒間通訊的能力,可以跨程序使用。

缺點:速度慢於使用者模式、混合模式構造,稍快於 mutex。

在 .net 4.0 時候引入了manualreseteventslim來提高效能。下面是 msdn 的原話:

在 .net framework 4 版中,當等待時間預計非常短時,並且當事件不會跨越程序邊界時,可使用 system.threading.manualreseteventslim 類以獲得更好的效能。當等待事件變為已發出訊號狀態的過程中,manualreseteventslim 短時間內會使用繁忙旋轉。當等待時間很短時,旋轉的開銷相對於使用等待控制代碼來進行等待的開銷會少很多。但是,如果事件在某個時間段內沒有變為已發出訊號狀態,則 manualreseteventslim 會採用常規的事件處理等待。

--- 《manualresetevent 和 manualreseteventslim》

manualreseteventslim 的用法與 manualresetevent 幾乎相似,只是原先使用 waitone 的地方需要使用 wait 代替。

優點:提供執行緒間通訊的能力。

缺點:不能跨程序使用,速度快於核心模式構造。

本篇文章所解決的是當兩個或多個執行緒之間需要按某種順序執行的時候,執行緒間的同步問題。如果在開發中遇到兩個執行緒需要按某種順序先後執行的,則應該考慮使用 manualresetevent 或 autoresetevent。

執行緒同步的情景之一

從本篇文章開始,我將陸續介紹多執行緒中會遇到的三種情況。情景一 此茅坑有主了 大錘 我擦,居然乙個茅坑有兩個人在用。大錘 啊,忍不住了,一起擠擠吧 叫獸 舒坦了,先走了。叫獸按下了沖水開關.嘩啦啦.大錘 你妹啊,衝什麼水啊,衝得我一身 解決方案 為了解決這種混亂的情況,管理員給茅坑加了道門,一次只允...

C 執行緒同步的三類情景分析

c 已經提供了我們幾種非常好用的類庫如 backgroundworker thread task等,借助它們,我們就能夠分分鐘編寫出乙個多執行緒的應用程式。比如這樣乙個需求 有乙個 winform 窗體,點選按鈕後,會將窗體中的資料匯出到乙個 output.pdf 檔案中。原先的 沒有採用多執行緒技...

執行緒同步(三)

1 中斷的應用場景 執行緒a.start 正瘋狂地計算乙個任務,這時我們抽風了,不想讓它繼續計算了,我們可以呼叫執行緒a.interrupt 那麼執行緒a通過 不斷輪詢boolean flag thread.interrupted 得到狀態位,即中斷通知資訊,再由執行緒a自己決定是否結束執行緒。當執...