秒杀多线程第七篇 经典线程同步 互斥量Mutex
閱讀本篇之前推薦閱讀以下姊妹篇:
《秒殺多線程第四篇一個(gè)經(jīng)典的多線程同步問題》
《秒殺多線程第五篇經(jīng)典線程同步關(guān)鍵段CS》
《秒殺多線程第六篇經(jīng)典線程同步事件Event》
?
前面介紹了關(guān)鍵段CS、事件Event在經(jīng)典線程同步問題中的使用。本篇介紹用互斥量Mutex來(lái)解決這個(gè)問題。
互斥量也是一個(gè)內(nèi)核對(duì)象,它用來(lái)確保一個(gè)線程獨(dú)占一個(gè)資源的訪問。互斥量與關(guān)鍵段的行為非常相似,并且互斥量可以用于不同進(jìn)程中的線程互斥訪問資源。使用互斥量Mutex主要將用到四個(gè)函數(shù)。下面是這些函數(shù)的原型和使用說(shuō)明。
第一個(gè)?CreateMutex
函數(shù)功能:創(chuàng)建互斥量(注意與事件Event的創(chuàng)建函數(shù)對(duì)比)
函數(shù)原型:
HANDLECreateMutex(
??LPSECURITY_ATTRIBUTESlpMutexAttributes,
??BOOLbInitialOwner,?????
??LPCTSTRlpName
);
函數(shù)說(shuō)明:
第一個(gè)參數(shù)表示安全控制,一般直接傳入NULL。
第二個(gè)參數(shù)用來(lái)確定互斥量的初始擁有者。如果傳入TRUE表示互斥量對(duì)象內(nèi)部會(huì)記錄創(chuàng)建它的線程的線程ID號(hào)并將遞歸計(jì)數(shù)設(shè)置為1,由于該線程ID非零,所以互斥量處于未觸發(fā)狀態(tài)。如果傳入FALSE,那么互斥量對(duì)象內(nèi)部的線程ID號(hào)將設(shè)置為NULL,遞歸計(jì)數(shù)設(shè)置為0,這意味互斥量不為任何線程占用,處于觸發(fā)狀態(tài)。
第三個(gè)參數(shù)用來(lái)設(shè)置互斥量的名稱,在多個(gè)進(jìn)程中的線程就是通過名稱來(lái)確保它們?cè)L問的是同一個(gè)互斥量。
函數(shù)訪問值:
成功返回一個(gè)表示互斥量的句柄,失敗返回NULL。
?
第二個(gè)打開互斥量
函數(shù)原型:
HANDLEOpenMutex(
?DWORDdwDesiredAccess,
?BOOLbInheritHandle,
?LPCTSTRlpName?????//名稱
);
函數(shù)說(shuō)明:
第一個(gè)參數(shù)表示訪問權(quán)限,對(duì)互斥量一般傳入MUTEX_ALL_ACCESS。詳細(xì)解釋可以查看MSDN文檔。
第二個(gè)參數(shù)表示互斥量句柄繼承性,一般傳入TRUE即可。
第三個(gè)參數(shù)表示名稱。某一個(gè)進(jìn)程中的線程創(chuàng)建互斥量后,其它進(jìn)程中的線程就可以通過這個(gè)函數(shù)來(lái)找到這個(gè)互斥量。
函數(shù)訪問值:
成功返回一個(gè)表示互斥量的句柄,失敗返回NULL。
?
第三個(gè)觸發(fā)互斥量
函數(shù)原型:
BOOLReleaseMutex?(HANDLEhMutex)
函數(shù)說(shuō)明:
訪問互斥資源前應(yīng)該要調(diào)用等待函數(shù),結(jié)束訪問時(shí)就要調(diào)用ReleaseMutex()來(lái)表示自己已經(jīng)結(jié)束訪問,其它線程可以開始訪問了。
?
最后一個(gè)清理互斥量
由于互斥量是內(nèi)核對(duì)象,因此使用CloseHandle()就可以(這一點(diǎn)所有內(nèi)核對(duì)象都一樣)。
?
接下來(lái)我們就在經(jīng)典多線程問題用互斥量來(lái)保證主線程與子線程之間的同步,由于互斥量的使用函數(shù)類似于事件Event,所以可以仿照上一篇的實(shí)現(xiàn)來(lái)寫出代碼:
[cpp]?view plaincopy運(yùn)行結(jié)果如下圖:
可以看出,與關(guān)鍵段類似,互斥量也是不能解決線程間的同步問題。
???????聯(lián)想到關(guān)鍵段會(huì)記錄線程ID即有“線程擁有權(quán)”的,而互斥量也記錄線程ID,莫非它也有“線程擁有權(quán)”這一說(shuō)法。
???????答案確實(shí)如此,互斥量也是有“線程擁有權(quán)”概念的。“線程擁有權(quán)”在關(guān)鍵段中有詳細(xì)的說(shuō)明,這里就不再贅述了。另外由于互斥量常用于多進(jìn)程之間的線程互斥,所以它比關(guān)鍵段還多一個(gè)很有用的特性——“遺棄”情況的處理。比如有一個(gè)占用互斥量的線程在調(diào)用ReleaseMutex()觸發(fā)互斥量前就意外終止了(相當(dāng)于該互斥量被“遺棄”了),那么所有等待這個(gè)互斥量的線程是否會(huì)由于該互斥量無(wú)法被觸發(fā)而陷入一個(gè)無(wú)窮的等待過程中了?這顯然不合理。因?yàn)檎加媚硞€(gè)互斥量的線程既然終止了那足以證明它不再使用被該互斥量保護(hù)的資源,所以這些資源完全并且應(yīng)當(dāng)被其它線程來(lái)使用。因此在這種“遺棄”情況下,系統(tǒng)自動(dòng)把該互斥量?jī)?nèi)部的線程ID設(shè)置為0,并將它的遞歸計(jì)數(shù)器復(fù)置為0,表示這個(gè)互斥量被觸發(fā)了。然后系統(tǒng)將“公平地”選定一個(gè)等待線程來(lái)完成調(diào)度(被選中的線程的WaitForSingleObject()會(huì)返回WAIT_ABANDONED_0)。
?
下面寫二個(gè)程序來(lái)驗(yàn)證下:
第一個(gè)程序創(chuàng)建互斥量并等待用戶輸入后就觸發(fā)互斥量。第二個(gè)程序先打開互斥量,成功后就等待并根據(jù)等待結(jié)果作相應(yīng)的輸出。詳見代碼:
第一個(gè)程序:
[cpp]?view plaincopy第二個(gè)程序:
[cpp]?view plaincopy運(yùn)用這二個(gè)程序時(shí)要先啟動(dòng)程序一再啟動(dòng)程序二。下面展示部分輸出結(jié)果:
結(jié)果一.二個(gè)進(jìn)程順利執(zhí)行完畢:
結(jié)果二.將程序一中//exit(0);前面的注釋符號(hào)去掉,這樣程序一在觸發(fā)互斥量之前就會(huì)因?yàn)閳?zhí)行exit(0);語(yǔ)句而且退出,程序二會(huì)收到WAIT_ABANDONED消息并輸出“擁有互斥量的進(jìn)程意外終止”:
有這個(gè)對(duì)“遺棄”問題的處理,在多進(jìn)程中的線程同步也可以放心的使用互斥量。
?
最后總結(jié)下互斥量Mutex:
1.互斥量是內(nèi)核對(duì)象,它與關(guān)鍵段都有“線程所有權(quán)”所以不能用于線程的同步。
2.互斥量能夠用于多個(gè)進(jìn)程之間線程互斥問題,并且能完美的解決某進(jìn)程意外終止所造成的“遺棄”問題。
?
下一篇《秒殺多線程第八篇 經(jīng)典線程同步 信號(hào)量Semaphore》將介紹使用信號(hào)量Semaphore來(lái)解決這個(gè)經(jīng)典線程同步問題。
?
?
轉(zhuǎn)載請(qǐng)標(biāo)明出處,原文地址:http://blog.csdn.net/morewindows/article/details/7470936
如果覺得本文對(duì)您有幫助,請(qǐng)點(diǎn)擊‘頂’支持一下,您的支持是我寫作最大的動(dòng)力,謝謝。
總結(jié)
以上是生活随笔為你收集整理的秒杀多线程第七篇 经典线程同步 互斥量Mutex的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 秒杀多线程第五篇 经典线程同步 关键段C
- 下一篇: 秒杀多线程第九篇 经典线程同步总结 关键