只能從內部開啟的一種鎖
不得不說,小明是一個動手能力非常強的同學。學習程式設計就是如此,動手一試,強過所有!
不過小明做的模擬程式並不完善,遇到了一些問題,其中最典型的就是不知道怎麼控制任務序列執行。因為只有一個煮麵的小哥和一個調味的阿姨!但是小明寫的程式中,煮麵的小哥在同時煮很多面,阿姨也同時給很多面調味。
小明發現這顯然沒有很好的模擬出早餐店內的流水線!所以他在今天的的課程開始之前,早早的趕到教室,和我好好的溝通了一陣子。
所以今天的內容,小明已經提前學習了一些了。因為今天的內容,正是關於多執行緒之間,如何解決資源衝突與共享問題的。
鎖課前小明向我表明他所遇到的問題之後,我和小明的聊天如下:
老師:你家有幾個衛生間啊?
小明:一個
老師:衛生間的門,裝鎖了嗎?
小明:裝了
老師:為什麼要裝鎖呢?
小明:老師,我好像有點明白了。。。。
沒錯,程式界,也發明了一種鎖,用於給一些特定資源加鎖,從而避免多個執行緒對於同一個資源的同時操作導致的不一致問題。
例項演示下面我們看一段簡單的演示例項程式:
class Program{ static long uniqueRes = 0; // 唯一資源 static void DealRes() { // 用1萬次加法,模擬大量操作 for (int i = 0; i < 10000; i++) { uniqueRes += 1; } } static void Main(string[] args) { Console.WriteLine("Hello Thread Locker!"); // 開啟4個執行緒,模擬同時操作資源 var thds = new List<Thread>(); for (int i = 0; i < 4; i++) { var t = new Thread(DealRes); thds.Add(t); t.Start(); } foreach (var t in thds) { t.Join(); } Console.WriteLine($"sum: {uniqueRes}"); Console.ReadKey(); }}
程式中,透過4個執行緒模擬對資源的同時操作,每一個執行緒對資源執行1萬次加法,其執行結果如下:
不一致問題
可以看到,執行的結果不可預期,可能正確,也可能不正確,錯的結果各種各樣。這就是多個執行緒,對於一個唯一資源同時操作的惡果。
在實際生產環境中,千萬不能這麼做。
改進例項演示我看了一眼小明,成竹在胸的樣子,我想他已經知道怎麼解決這個問題了。
其實很簡單,在C#中,使用鎖是很簡單的,我們只需要對DealRes函式進行簡單修改即可:
// 鎖物件static object locker = new object();static void DealRes(){ // 將資源鎖上 lock (locker) { // 用1萬次加法,模擬大量操作 for (int i = 0; i < 10000; i++) { uniqueRes += 1; } }}
多次執行結果如下:
正確的執行結果
小明看到這裡,忍不住發言道:
這樣程式就不是並行運行了,在這一個小例項中,開啟多執行緒沒有任何意義,反而會因為開啟執行緒而浪費資源,降低程式的執行速度。
但是用在早餐店的模擬程式中,就很合適,給煮麵小哥和調味阿姨,分別加上鎖,就可以正常的模擬實際的流水線作業了。
其他同學,紛紛給小明豎起了大拇指。
C#中其他鎖機制在System.Threading名稱空間下面,還有以下幾個用於控制資源訪問的類:
Monitor和lock的原理一致,lock正是基於Monitor實現的,是C#中使用最廣泛的一種同步機制。
Mutex也是一種常用的互斥鎖,相比於Monitor,Mutex可以命名,從而可以實現跨程序之間的同步控制。
ReaderWriterLockSlim這是一種可以實現寫互斥,讀寫互斥的鎖,可以實現對於資源的讀寫分別控制的鎖。可替代ReaderWriterLock。
SemaphoreSlim這是一種可以控制資源池的鎖,允許一定數量的執行緒進入訪問共享資源。通常用於限流這類場景。可替代Semaphore。
WaitHandle這是一種提供等待機制的同步介面,其派生類 EventWaitHandle,AutoResetEvent,ManualResetEvent可以實現基於事件的資源訪問控制。其中ManualResetEventSlim可替代ManualResetEvent。
這時我看向小明,他的臉上,也出現了愁容!這次的鎖有點多,不太好消化的樣子。
小明的臉上,終於又出現了笑容!
聰明的小明同學
踩坑記錄暫無
下期預告下面是給同學們準備的乾貨,正在陸續發貨中哦:
多執行緒死鎖問題
Task
Parallel
await/async
Linq與PLinq (ParallelEnumerable)
。。。 。。。