線(xiàn)程同步篇 (中):同步工具類(lèi)的介紹
·1 上篇回顧
·2 繼續介紹基元內核模式中的 monitor類(lèi)
·3 同步句柄:WaitHandle
·4 EventWaitHandle,AutoResetEvent和ManualResetEvent
·5 同步互斥mutex類(lèi)
·6 簡(jiǎn)單說(shuō)明下mutex和monitor的區別
·7 選擇我們需要的同步工具
·8 本章總結
1 上篇回顧
很抱歉好久沒(méi)寫(xiě)博客了,由于工作太忙,所以最近一段時(shí)間落下了,讓我們開(kāi)始上一篇向大家介紹了下線(xiàn)程同步中的一些重要概念包括:
基元內核模式,基元用戶(hù)模式,原子性,然后由陸續介紹了基元用戶(hù)模式中的Validated,Interloced 和ReaderWriterLock 類(lèi),同時(shí)也簡(jiǎn)單
介紹了下基元內核模式中的lock關(guān)鍵字,本章再讓我們繼續深入了解其他的一些同步工具類(lèi)
2 繼續介紹基元內核模式中的Monitor類(lèi)
首先上圖讓大家有個(gè)初步的印象:
Monitor類(lèi)也是同步機制中比較重要的一個(gè)類(lèi),它屬于基元內核模式中的一種,也是上一章中與lock關(guān)鍵字有著(zhù)密切關(guān)系,Monitor類(lèi)采取
排他鎖來(lái)進(jìn)行對共享區的同步,當一個(gè)線(xiàn)程進(jìn)入共享區時(shí),會(huì )取得排他鎖的控制權,其他線(xiàn)程則必須等待,大伙注意,這里有2個(gè)重要的線(xiàn)
程狀態(tài)需要在說(shuō)明下
1:等待隊列:
等待進(jìn)入共享區的線(xiàn)程會(huì )首先進(jìn)入到等待隊列中,等待持有排他鎖的線(xiàn)程通知某個(gè)等待線(xiàn)程進(jìn)入到就緒隊列中,注意(只有擁
有排他鎖的線(xiàn)程才能進(jìn)行互換通知功能,甚至該線(xiàn)程能夠喚醒一堆的等待線(xiàn)程進(jìn)入到就緒隊列中)
2:就緒隊列
等待隊列中的某個(gè)線(xiàn)程被持有排他鎖的線(xiàn)程喚醒放入到就緒隊列中,等待獲取排他鎖的機會(huì ),這樣一個(gè)周期便可以連接起來(lái),
線(xiàn)程從等待到被喚醒到就緒狀態(tài),然后獲取排他鎖進(jìn)如共享區操作,然后交出排他鎖等待或者睡眠,直到再次被喚醒。
在這里強調下Monitor是個(gè)十分容易產(chǎn)生死鎖的同步類(lèi),其原因是:
1.當一個(gè)線(xiàn)程試圖去請求鎖對象時(shí),它不是處在等待隊列,而是就緒隊列,如果需要讓其進(jìn)入等待隊列,則必須使用Wait方法
2.當一個(gè)線(xiàn)程釋放鎖對象時(shí)是不會(huì )通知等待隊列中的線(xiàn)程進(jìn)入到就緒隊列,需要通過(guò)Palse方法
3.線(xiàn)程啟動(dòng)的時(shí)候,線(xiàn)程是處于就緒狀態(tài)的
4.就算處于就緒狀態(tài)的線(xiàn)程被cpu選中,但是一旦數據被鎖定,那個(gè)線(xiàn)程還是無(wú)法獲取到控制權
其實(shí)大家了解原因后對于monitor已經(jīng)算了解,這正是monitor的機制
了解了上述機制后,大家可以開(kāi)始理解該類(lèi)比較重要的幾個(gè)方法:
Monitor. Enter(Object);
該方法旨在宣布當前線(xiàn)程進(jìn)入了臨界區,持有了排他鎖,其他線(xiàn)程繼續等待,直到該線(xiàn)程離開(kāi)共享區交出排他鎖給就緒隊列中的一個(gè)線(xiàn)程
Monitor. Exit(Object);
當持有共享鎖的線(xiàn)程執行完任務(wù)之后,該線(xiàn)程變通過(guò)這個(gè)方法離開(kāi)共享區,臨走前可以操作其喚醒一個(gè)或一堆的等待線(xiàn)程
Monitor.Palse(Object)和Monitor.Palse(Object)
這兩個(gè)方法比較復雜和相似,也就是喚醒(改變)其他線(xiàn)程狀態(tài)的方法,持有排他鎖的線(xiàn)程利用這兩個(gè)方法通知其他線(xiàn)程進(jìn)入到就緒隊列,離開(kāi)等待隊列
Monitor.Wait(Object)
這個(gè)方法也是非常的重要,假如在共享區內的線(xiàn)程執行了wait方法后,該線(xiàn)程會(huì )被放入等待隊列中,從而失去了排他鎖的控制權,就緒隊列中的下一個(gè)線(xiàn)程就進(jìn)入到了臨界區
Monitor.TryEnter(Object, Boolean))
有時(shí)其他線(xiàn)程希望通過(guò)進(jìn)行嘗試的方式主動(dòng)去爭取排他鎖的控制權,這個(gè)方法便能實(shí)現這個(gè)功能,同時(shí)通過(guò)一個(gè)BOOL參數來(lái)指示會(huì )否占有了排他鎖
文字介紹為了讓大伙更好的理解Monitor類(lèi)的本質(zhì),接下來(lái)就上很簡(jiǎn)單代碼讓我們更深入的了解
/// <summary>
/// 開(kāi)啟2個(gè)寫(xiě)線(xiàn)程,2個(gè)讀線(xiàn)程演示
/// </summary>
/// <param name="args"></param>
static void Main(string[] args)
{
Thread t1 = new Thread(new ThreadStart(WriteInShareArea));
Thread t3 = new Thread(new ThreadStart(WriteInShareArea));
Thread t2 = new Thread(new ThreadStart(Read));
Thread t4= new Thread(new ThreadStart(Read));
Console.WriteLine("t1's id={0}", t1.ManagedThreadId);
Console.WriteLine("t2's id={0}", t2.ManagedThreadId);
Console.WriteLine("t3's id={0}", t3.ManagedThreadId);
t1.Start();
t3.Start();
t2.Start();
t4.Start();
Console.Read();
}
/// <summary>
/// 讀數據,首先是先讓讀線(xiàn)程等待,當寫(xiě)線(xiàn)程寫(xiě)完執行 Pulse 方法后,喚醒讀線(xiàn)程繼續工作
/// </summary>
private static void Read()
{
while (true)
{
Monitor.Enter(lockObj); //讀線(xiàn)程啟動(dòng)時(shí)默認就緒隊列
//讀線(xiàn)程執行到這里時(shí)會(huì )掛起進(jìn)入等待隊列
Monitor.Wait(lockObj, 4000);
Console.WriteLine("Thread{0} can read nao", Thread.CurrentThread.ManagedThreadId);
Console.WriteLine("Thread{0} reading...............", Thread.CurrentThread.ManagedThreadId);
Thread.Sleep(3000);
Monitor.Exit(lockObj);
}
}
/// <summary>
/// 寫(xiě)數據,當寫(xiě)線(xiàn)程寫(xiě)完執行 Pulse 方法后,喚醒讀線(xiàn)程繼續工作
/// </summary>
private static void WriteInShareArea()
{
while (true)
{
Thread.Sleep(1000);
Monitor.Enter(lockObj);
Console.WriteLine("Thread{0} change data nao", Thread.CurrentThread.ManagedThreadId);
Console.WriteLine("Thread{0} changing...............", Thread.CurrentThread.ManagedThreadId);
Thread.Sleep(1000);
//喚醒讀線(xiàn)程進(jìn)入就緒隊列
Monitor.Pulse(lockObj);
Monitor.Exit(lockObj);
}
}
執行結果:
3 同步句柄:WaitHandle
WaitHandle可以說(shuō)是本章中許多同步對象的基類(lèi)包括前后文中的AutoResetEvent,ManualResetEvent,mutex 和Semaphore都是其子類(lèi),
waitHandle是個(gè)抽象類(lèi),主要的功能從字面上就能看的出來(lái),等待句柄,不錯 WaitHandle非常的神奇,它容納了一個(gè)WIN32的內核對象句柄,線(xiàn)程
會(huì )等待內核對象的消息,當然內核對象也會(huì )等待接收信號,一旦接收到信號則會(huì )通知當前線(xiàn)程,這是一種復雜的操作系統調度原理,大家可以參考
WINDOWS核心編程等書(shū)繼續深入了解下,本文旨在說(shuō)明下waitHandle的概念和一些簡(jiǎn)單的介紹,這里在為waitHandle打個(gè)比方:
當你想穿過(guò)馬路時(shí),如果信號燈為紅色則你只能等待,如果轉變成綠燈的話(huà),你就可以通行,其實(shí)waitHandle的作用就是紅綠燈的作用,聰明的的你
肯定想到了,那我們可以將線(xiàn)程同步信號燈放入線(xiàn)程池中么?哈哈當然可以,不僅可以放一根,而且可以放入一堆WaitHadle對象。言歸正傳:WaitHadle
也有2個(gè)信號” Signaled” and “NonSignaled” ,前者可以理解為綠燈,綠燈狀態(tài)時(shí)WaitOne方法無(wú)效,當前線(xiàn)程不會(huì )被阻止,后者可以理解為紅燈,當底
層內核對象接受到信號時(shí),通知某個(gè)當前線(xiàn)程可以進(jìn)入到共享區(臨界區)其余的必須等待,不過(guò)基于抽象類(lèi)的考慮,waitHandle沒(méi)有喚醒線(xiàn)程的set方法,
而讓其子類(lèi)實(shí)現了,所以WaitHandle 還是完全體現其”等啊等,直到提示可以通過(guò)或者直接奔潰(超時(shí)異常)”的特色
既然waitHandle只有阻塞等待的作用,那我們來(lái)看下它的幾個(gè)奇妙的方法:
1 bool WaitOne(): 等待一個(gè)通過(guò)當前waitHandle指定的內核對象收到信號后返回true,否則返回false
2 bool WaitAll():等待waitHandle[]中所有的內核對象都收到信號后返回true,否則返回false
3 bool WaitAny();等待waitHandle[]中內核對象都收到信號后返回true,否則返回false
4 bool SignalAndWait():這個(gè)方法無(wú)法用文字表達清楚,但是大伙先可以理解成這樣:自動(dòng)的向內核對象發(fā)送信息,等待另一個(gè)內核對象接收到信號,
如果另一個(gè)內核對象接受到信號則返回TRUE,這牽涉到了復雜的”混合鎖”的機制,所以本文不再詳細說(shuō)明,后章會(huì )詳細介紹混合鎖機制
接著(zhù)讓我們來(lái)看下WaitHandle的幾個(gè)派生類(lèi)結構,后文中將一一介紹:
EventWaitHandle
AutoResetEvent
ManualResetEvent
Mutex
Semaphore (將在下章詳細介紹)
最后上一個(gè)圖來(lái)表示下WaitHandle的工作原理
大胖子就是個(gè)waitHandle(只負責讓當前線(xiàn)程等待,也可以雇傭多個(gè)大胖子,內核對象接受到信號后通知大胖子,然后大胖子放人進(jìn)入club)
4 EventWaitHandle , AutoResetEvent和ManualResetEvent
相信大家對于WaitHandle已經(jīng)有所了解,接著(zhù)我們將來(lái)介紹下EventWaitHandle ,AutoResetEvent和ManualResetEvent的一些概念和
使用方法(用列表的方式):
EventWaitHandle:
1具有WaitHandle的一些阻塞線(xiàn)程的wait方法
2具有Set方法來(lái)釋放被阻塞的當前線(xiàn)程
3具有終止狀態(tài)和非終止狀態(tài)
4具有自己的重置模式可以選擇:自動(dòng)重置和手動(dòng)重置,當eventWaitHandle對象調set方法后,eventWaitHandle會(huì )更具重置模式自動(dòng)重置或手動(dòng)
重置,重置后會(huì )立刻阻塞當前線(xiàn)程(當前線(xiàn)程調用Wait方法后阻塞),如果一直不重置,將無(wú)法阻塞當前線(xiàn)程
5 重置模式在初始化eventWaitHandle對象的第二個(gè)參數中設置
6 終止狀態(tài)不會(huì )導致阻塞線(xiàn)程,非終止裝態(tài)會(huì )導致阻塞當前線(xiàn)程
7 可以調用Reset()方法將狀態(tài)設置成非終止裝態(tài)來(lái)阻塞線(xiàn)程
AutoResetEvent
1 具有父類(lèi)EventWaitHandle 的功能
2 同樣具有set方法,但是每次只能喚醒一個(gè)線(xiàn)程
3 同樣具有終止狀態(tài)和非終止狀態(tài)
4 重置模式為自動(dòng)(其實(shí)就是一直處于非終止狀態(tài),等待新的線(xiàn)程,waitOne方法將不會(huì )阻塞線(xiàn)程,直到新的線(xiàn)程進(jìn)入臨界區后,自動(dòng)將模式設置成非
終止模式,阻塞其他線(xiàn)程,如果一直沒(méi)有新的線(xiàn)程進(jìn)入,那只能永遠處于終止狀態(tài))
5 也可以調用Reset()方法將狀態(tài)設置成非終止裝態(tài)來(lái)阻塞線(xiàn)程
6 可以在構造函數中設置默認的狀態(tài)(終止狀態(tài)和非終止狀態(tài))
簡(jiǎn)單示例:
/// <summary>
/// 演示waitHandle和AutoResetEvent的同步方法
/// </summary>
class Program
{
static WaitHandle[] waitHandle;
static void Main(string[] args)
{
//委托集合
List<Action> ls = new List<Action>
{
()=>{ Console.Write("A");},
()=>{ Console.Write("B");},
()=>{ Console.Write("C");},
()=>{ Console.Write("D");},
()=>{ Console.Write("E");},
()=>{ Console.Write("F");},
()=>{ Console.Write("G");},
};
InvokeAllActions(ls);
}
/// <summary>
/// 利用線(xiàn)程池對委托集合中的所有委托進(jìn)行觸發(fā),同時(shí)通過(guò)AutoResetEvent 進(jìn)行同步
/// </summary>
/// <param name="actionList"></param>
static void InvokeAllActions(List<Action> actionList)
{
waitHandle = new WaitHandle[actionList.Count];
if (actionList == null || actionList.Count <= 0) return;
int i = 0;
actionList.ForEach((action) =>
{
//創(chuàng )建AutoResetEvent對象
waitHandle[i] = new AutoResetEvent(false);
//將AutoResetEvent對象作為參數放入線(xiàn)程池
ThreadPool.QueueUserWorkItem(new WaitCallback((handle) =>
{
//觸發(fā)委托
action.Invoke();
Thread.Sleep(new Random().Next(1000, 10000));
//委托執行完畢后發(fā)出信號,告訴其他線(xiàn)程可以進(jìn)入共享區
(handle as AutoResetEvent).Set();
}), waitHandle[i]);
if (i == actionList.Count - 1) return;
i++;
});
//注意WaitAll的使用方法,當主線(xiàn)程調用WaitAll方法時(shí),將等待所有的waitHandle接受到信號后才能通過(guò)
//信號通過(guò)Set()方法發(fā)出
WaitHandle.WaitAll(waitHandle);
}
}
輸出結果可能隨時(shí)發(fā)生變化
ManualResetEvent
1 具有父類(lèi)EventWaitHandle 的功能
2 同樣具有set方法,但是每次可以喚醒一個(gè)或多個(gè)線(xiàn)程
3 同樣具有終止狀態(tài)和非終止狀態(tài)
4 重置模式為手動(dòng)(和AutoResetEvent不同的的是執行waitOne方法后,它不會(huì )自動(dòng)將模式設置成非終止模式,也就是說(shuō)會(huì )一直保持有信號狀態(tài),除非
程序員手工寫(xiě)上Reset方法讓其狀態(tài)成為非終止狀態(tài),阻塞其他線(xiàn)程,同理,一旦執行set方法后ManualResetEvent也就可以同時(shí)喚醒多個(gè)線(xiàn)程繼續執行)
簡(jiǎn)單示例:(稍后補上)
5 同步互斥mutex類(lèi)
Mutext 出現的比monitor更早,而且傳承自COM,當然,waitHandle也是它的父類(lèi),它繼承了其父類(lèi)的功能,有趣的是Mutex的脾氣非常的古怪,它
允許同一個(gè)線(xiàn)程多次重復訪(fǎng)問(wèn)共享區,但是對于別的線(xiàn)程那就必須等待,同時(shí),它甚至支持不同進(jìn)程中的線(xiàn)程同步,這點(diǎn)更能體現他的優(yōu)勢,但是劣勢也是顯而
易見(jiàn)的,那就是巨大的性能損耗和容易產(chǎn)生死鎖的困擾,所以除非需要在特殊場(chǎng)合,否則 我們盡量少用為妙,這里并非是將mutex的缺點(diǎn)說(shuō)的很?chē)乐?,而是建議
大家在適當的場(chǎng)合使用更為適合的同步方式,mutex 就好比一個(gè)重量型的工具,利用它則必須付出性能的代價(jià)。
接著(zhù)讓我們了解下mutex的工作方式,同樣我們用列表的方式更簡(jiǎn)潔
1. mutex類(lèi)通過(guò)WaitOne 方法阻止另一個(gè)線(xiàn)程的進(jìn)入共享區,但是對于擁有相同的互斥體的線(xiàn)程,WaitOne方法無(wú)效,如果其他線(xiàn)程想獲取互斥體的話(huà),必須等
待擁有互斥體的線(xiàn)程執行ReleasMutex方法后釋放該互斥體后才有可能獲取
2. 每次使用WaitOne 方法后都需要使用ReleasMutex方法釋放互斥體的所屬權,waitOne方法和ReleaMutex方法使用次數必須一致,對于遞歸鎖和混合鎖將
非常復雜
3. 同樣具有終止狀態(tài)和非終止狀態(tài)
4. ReleaMutex 后互斥體的狀態(tài)設定為終止,直到其他線(xiàn)程占有互斥體,但是如果沒(méi)有線(xiàn)程擁有互斥體的話(huà),該互斥體的狀態(tài)便終止了
5. 父類(lèi)WaitHandle負責接收信號,當接收到信號后方能讓其他線(xiàn)程進(jìn)入臨界區或是獲取到互斥體的所屬權
6. 能否在進(jìn)程中互相同步取決于該Mutex對象是否有名字,這似乎有點(diǎn)奇怪,但是大家仔細想下,如果跨進(jìn)程實(shí)現同步的話(huà),那么其他進(jìn)程假如
也有一些Mutex的吧,那么根本無(wú)法告訴在不同進(jìn)程中的線(xiàn)程是這個(gè)互斥體mutex對象負責這方面的同步工作,或許大家會(huì )問(wèn)如果名字一樣怎么辦?
好問(wèn)題,微軟也想到了,而且它是通過(guò)再制造一個(gè)新的互斥體替代,這樣和不同進(jìn)程間的互斥體保持唯一互補沖突,但是這個(gè)選項在構造函數中,
下面的構造函數也會(huì )闡述這點(diǎn)
7. 對于沒(méi)有名字的mutex對象,我們稱(chēng)之為局部互斥體,相反則是全局互斥體
最后來(lái)簡(jiǎn)單介紹下Mutex類(lèi)的幾個(gè)重要方法*
1.Bool WaitOne():阻止當前線(xiàn)程,直到收到信號后才能繼續,如果一直沒(méi)有接受到信號則永遠不會(huì )返回而被阻塞,負責接受信號是比較重要的同步類(lèi)WaitHandle,
關(guān)于這個(gè)類(lèi),下文中會(huì )有詳細闡述
2.void ReleaseMutex()
這個(gè)方法非常重要,它是配合waitOne方法而存在的,簡(jiǎn)單的說(shuō)擁有互斥體mutex控制權的線(xiàn)程如果不需要互斥體的話(huà),則使用該方法釋放mutex,再次提醒下
WaitOne方法和ReleaseMutex方法的使用次數必須一致
3. Mutex OpenExisting(string mutexName)
該方法相對于mutex來(lái)說(shuō)也是必不可少,它的作用是查找mutex是否存在,如果不存在的話(huà),則會(huì )引發(fā)WaitHandleCannotBeOpenedException,我們可以再這
個(gè)捕獲異常中實(shí)現mutex對象的創(chuàng )建
Mutex類(lèi)的構造方法:
1.Mutex()
用無(wú)參數的構造函數得到的Mutex沒(méi)有任何名稱(chēng),而進(jìn)程間無(wú)法通過(guò)變量的形式共享數據,所以沒(méi)有名稱(chēng)的Mutex也叫做局部(Local)Mutex。另外,
這樣創(chuàng )建出的Mutex,創(chuàng )建者對這個(gè)實(shí)例并沒(méi)有擁有權,仍然需要調用WaitOne()去請求所有權。
2.Mutex(Boolean initiallyOwned)
與上面的構造函數一樣,它只能創(chuàng )建沒(méi)有名稱(chēng)的局部Mutex,無(wú)法用于進(jìn)程間的同步。Boolean參數用于指定在創(chuàng )建者創(chuàng )建Mutex后,
是否立刻獲得擁有權,因此Mutex(false)等效于Mutex()。
3.Mutex(Boolean initiallyOwned, String name)
在這個(gè)構造函數里我們除了能指定是否在創(chuàng )建后獲得初始擁有權外,還可以為這個(gè)Mutex取一個(gè)名字。只有這種命名的Mutex才可以被其它應用程序域中的程序所使用,因此
這種Mutex也叫做全局(Global)Mutex。 如果String為null或者空字符串,那么這等同于創(chuàng )建一個(gè)未命名的Mutex。因為可能有其他程序先于你創(chuàng )建了同名的Mutex,
因此返回的 Mutex實(shí)例可能只是指向了同名的Mutex而已。但是,這個(gè)構造函數并沒(méi)有任何機制告訴我們這個(gè)情況。因此,如果要創(chuàng )建一個(gè)命名的Mutex,并且期 望知道這
個(gè)Mutex是否由你創(chuàng )建,最好使用下面兩個(gè)構造函數中的任意一個(gè)。最后,請注意name是大小寫(xiě)敏感的。
4.Mutex(Boolean initiallyOwned, String name, out Boolean createdNew):
頭兩個(gè)參數與上面的構造函數相同,第三個(gè)out參數用于表明是否獲得了初始的擁有權。這個(gè)構造函數應該是我們在實(shí)際中使用較多的。
5.Mutex(Boolean initiallyOwned, String name, out Booldan createdNew, MutexSecurity):
多出來(lái)的這個(gè)MutexSecurity參數,也是由于全局Mutex的特性所決定的。
同樣馬上上一個(gè)例子:
/// <summary>
/// 本示例通過(guò)多線(xiàn)程拷貝字符數組
/// </summary>
class Program
{
private static char[] testChars = "abcdefg".ToCharArray();
private static char[] backChars = new char[testChars.Length];
private static Mutex mutex = new Mutex(false,"myMutex");
static void Main(string[] args)
{
try
{
//尋找名為myMutex2的互斥體對象
Mutex mutex2= Mutex.OpenExisting("myMutex2", MutexRights.FullControl);
}
catch (WaitHandleCannotBeOpenedException e)
{
Console.WriteLine("the name of mutex is not exist, error message:{0}",e.Message);
}
for (int i = 0; i < testChars.Length; i++)
{
ThreadPool.QueueUserWorkItem(new WaitCallback(SetBackString));
}
Console.ReadLine();
}
static void SetBackString(object state=null)
{
///阻止當前線(xiàn)程,直到收到信號后才能繼續
mutex.WaitOne();
try
{
if (testChars.Length > 0)
{
//每次將test4的第一個(gè)字符串放入backChars,原始backChars.Length 減去被刪除一個(gè)char的testChars.length
Array.Copy(testChars, 0, backChars, backChars.Length - testChars.Length, 1);
Console.WriteLine("ThreadID:{0} the chart:{1} will insert into backChars,the string changed from backChars:{2}", Thread.CurrentThread.ManagedThreadId, testChars[0], string.Join(string.Empty, backChars));
//申明一個(gè)臨時(shí)char數組用來(lái)存放testChars,實(shí)際作用是刪除testChars的一個(gè)char
char[] temp = new char[testChars.Length-1];
//將不需要刪除的chars拷貝入temp
Array.Copy(testChars,1, temp, 0, testChars.Length-1);
testChars = temp;
}
}
catch
{
}
finally
{
//無(wú)論發(fā)生什么當前線(xiàn)程最終還是得釋放互斥體的控制權
mutex.ReleaseMutex();
}
}
}
顯示結果:
6 簡(jiǎn)單說(shuō)明下Mutex和Monitor的區別
相信大家看了上文后對于的Mutex和Monitor已經(jīng)有所了解,由于這2個(gè)工具類(lèi)可能用法上過(guò)于相似,當然區別也是不小
1. Monitor不是waitHandle的子類(lèi),它具有等待和就緒隊列的實(shí)際應用
2 Monitor無(wú)法跨進(jìn)程中實(shí)現線(xiàn)程同步,但是Mutex可以
3 相對而言?xún)烧哂忻黠@的性能差距,mutex相對性能較弱但是功能更為強大,monitor則性能比較好
4 兩者都是用鎖的概念來(lái)實(shí)現同步不同的是monitor一般在方法(函數)調用方加鎖;mutex一般在方法(函數)內部加鎖,即鎖定被調用端
以上是比較主要的區別,一些細節大家也可以繼續深究
7 選擇我們需要的同步工具
有時(shí)我們苦于在項目中尋找適合的同步工具,所以一下僅是個(gè)人觀(guān)點(diǎn),大伙可以討論或者發(fā)表自己的意見(jiàn)
1 處于性能要求考慮:可以考慮用基元用戶(hù)模式的同步工具,也就是前一篇中的一些同步工具,盡量不要考慮mutex因為其功能強大所以性能損失太多
2 處于功能考慮:如果項目中牽涉到復雜的同步而且不需要嚴格的性能要求,例如跨進(jìn)程,混合鎖或者遞歸鎖等等,則最好選擇基元內核模式中的同步工具
3 分布式開(kāi)發(fā),在各個(gè)服務(wù)間實(shí)現同步的話(huà),當然mutex是第一考慮
4 中小型項目大家可以隨意,根據業(yè)務(wù)需要決定
8 本章總結
本章介紹了monitor,waitHandle 及其一些子類(lèi)包括EventWaitHandle,AutoResetEvent,ManualResetEvent和mutex, 關(guān)于Semaphore 會(huì )在下章介紹,
不僅如此,下章還會(huì )介紹混合鎖和遞歸鎖,盡請期待!最后謝謝女友背后默默背后的支持,謝謝大家,還請大家能夠支持推薦下
聯(lián)系客服