NET多線程探索-互斥鎖,信號量,事件(小新和拆彈部隊友情演出)
2012-03-22 17:14 海不是藍 閱讀(2447) 評論(6) 收藏 舉報mutex互斥鎖-不準確的時鐘
概念性的東西:
互斥鎖是一個互斥的同步對象,一個時間只有一個線程可以獲取它。
前一篇文章中的時鐘程序我們這里用Mutex互斥鎖來實現。
class Program { static void Main(string[] args) { Clock C = new Clock(); C.RunClock(1); Console.Read(); } } public class Clock { public Mutex Mtx = new Mutex(); //開始運行時鐘,輸入運行分鐘 public void RunClock(Int32 Minute) { Thread T1 = new Thread((object Minute1) => { Int32 m = Convert.ToInt32(Minute1) * 60 / 2; while (m > 0) { DI(true); m--; } }); Thread T2 = new Thread((object Minute1) => { Int32 m = Convert.ToInt32(Minute1) * 60 / 2; while (m > 0) { DA(true); m--; } }); T1.Start(true); T2.Start(true); } public void DI(bool run) { Mtx.WaitOne(); if (!run) { Mtx.ReleaseMutex(); return; } else { Console.WriteLine("嘀"); Thread.Sleep(1000); Mtx.ReleaseMutex(); } } public void DA(bool run) { Mtx.WaitOne(); if (!run) { Mtx.ReleaseMutex(); return; } else { Console.WriteLine("嗒"); Thread.Sleep(1000); Mtx.ReleaseMutex(); } } }
這里我只發表下我的理解,還請個位園友自己認真分析下,畢竟我個人理解可能是錯誤的!
如果您發現我理解錯了,請在評論指出,我好及時學習更早!
Monitor的時鐘是使用了lock來鎖定,lock最后也會被編譯成為Monitor的Enter和Exit。
重點是Monitor在Pulse(obj)的時候已經就確定了另外一個等待obj被釋放的線程擁有了執行權!
而Mutex在ReleaseMutex在釋放鎖定之后,當前線程和其他等待線程都執行WaitOne,導致了線程執行權的爭奪!
隨著程序的運行,線程之間的爭奪激烈。
mutex互斥鎖-杯具的拆彈手
下面用互斥鎖實現個例子,一個炸彈,同時只能一個人拆彈,如果超過1個人就爆炸。
class Program { static void Main(string[] args) { 炸彈 b = new 炸彈(); b.拆彈(); b.拆彈(); Console.Read(); } } public class 炸彈 { private Int32 熱度 = 0; public Mutex m = new Mutex(); public void 拆彈() { Thread t = new Thread(炸彈內部); t.Start(); } private void 炸彈內部() { m.WaitOne(); 熱度++; Thread.Sleep(1000); if (熱度>1) { Console.WriteLine("炸彈爆炸!拆彈手見馬克思..."); m.ReleaseMutex(); return; } 熱度--; Console.WriteLine("炸彈安全拆除!拆彈手這個月獎金加倍..."); m.ReleaseMutex(); } }
拆彈手很幸運,這個月獎金加倍了。如果把Mutex去掉,那么馬克思就等著他們去聊天。
信號量-Semaphore
互斥鎖和同步都是鎖定一個資源,同時只讓一個線程去操作。
對于可以允許限定數量線程執行的情況互斥鎖就不適合了,這里就需要信號量。
信號量通過一個計數器來控制對共享資源的訪問,如果計數器的閑置數大于0,那么就允許訪問,如果=0就拒絕訪問。
public Semaphore(int initialCount, int maximumCount);
initialCount:可以同時授予的信號量的初始請求數。
maximumCount:可以同時授予的信號量的最大請求數。
public virtual bool WaitOne(); public int Release();
WaitOne():阻止當前線程,直到當前 System.Threading.WaitHandle 收到信號。
Release():退出信號量并返回前一個計數。
下面還是請出我們杯具的拆彈手來演示。
class Program { static void Main(string[] args) { //有關部門的磚家叫獸告訴拆彈手炸彈最多4個人同時拆 Int32 拆彈手人數 = 4; 炸彈 b = new 炸彈(拆彈手人數); while (拆彈手人數 > 0) { b.拆彈(); 拆彈手人數--; } Console.Read(); } } public class 炸彈 { private Int32 最高溫度 = 0; private Int32 熱度 = 0; private Semaphore S; public 炸彈(Int32 limit) { 最高溫度 = 3; S = new Semaphore(limit, limit); } public void 拆彈() { Thread t = new Thread(炸彈內部); t.Start(); } private void 炸彈內部() { S.WaitOne(); 熱度++; Thread.Sleep(1000); if (熱度 > 最高溫度) { Console.WriteLine("炸彈爆炸!拆彈手見馬克思..."); S.Release(); return; } 熱度--; Console.WriteLine("炸彈安全拆除!拆彈手這個月獎金加倍..."); S.Release(); } }
杯具的拆彈手,這里磚家叫獸錯誤指出最多4個人,而炸彈最高支持3個人!唉。。。
使用事件實現-幸福的小新
事件是另外一種同步對象,ManualResetEvent,AutoResetEvent2個類實現了事件同步的功能,都派生自EventWaitHandle類。
介紹下ManualResetEvent。
public ManualResetEvent(bool initialState); public virtual bool WaitOne(); public bool Reset(); public bool Set();
第一個是構造函數,傳入的變量是事件是否發出信號。
第二個是等待一個事件發出信號,期間是阻塞的。
第三個是重置事件為未發出信號狀態。
最后一個是設置事件為發出信號狀態。
ManualResetEvent和AutoResetEvent的主要實現都是相同,只有一點不同,就是ManualResetEvent需要手動設置事件為未發出信號,而AutoResetEvent是自動設置的。
野原新之助的一天
class Program { static void Main(string[] args) { ManualResetEvent mal = new ManualResetEvent(false); 美女姐姐 美女 = new 美女姐姐(); 小新 新之助 = new 小新(); Thread t1 = new Thread(new ParameterizedThreadStart(美女.美女姐姐上街)); Thread t2 = new Thread(new ParameterizedThreadStart(新之助.小新出動)); t1.Start(mal); t2.Start(mal); Console.Read(); } public class 美女姐姐 { public void 美女姐姐上街(object Mal) { Thread.Sleep(2000); Console.WriteLine("青春美麗的美女姐姐上街了..."); Thread.Sleep(1000); ((ManualResetEvent)Mal).Set(); } } public class 小新 { public 小新() { Thread.Sleep(1000); Console.WriteLine("小新拿著奶茶,猥瑣的躲在大街邊的綠化帶里..."); Thread.Sleep(1000); } public void 小新出動(object Mal) { ManualResetEvent Mal1 = (ManualResetEvent)Mal; Console.WriteLine("小新左右尋找美女姐姐..."); //等待美女姐姐的出現 Mal1.WaitOne(); Console.WriteLine("小新跑到美女姐姐面前,脫下小褲褲,亮出大象,開始跳大象舞..."); Console.WriteLine("屁股扭扭,“大象,大象,大象...”"); Mal1.Reset(); } } }
總結下吧!
寫了這么多,應該好好思考下這些同步方式,每種雖然大概思路是一樣!但是絕對有各自的特點。
有空大家還是看看CLR 3版中的線程核心部分,里面把這些同步的原理講的很清楚。
總之線程的水太深,慢慢游吧,下一篇把剩下的一些線程同步方式講下,然后就在最后對NET線程同步做個總結。






浙公網安備 33010602011771號