1.1 線程同步概述
如果沒(méi)有同步對(duì)象和操作系統(tǒng)對(duì)特殊事件監(jiān)視的能力,線程可能被迫使用有副作用的技術(shù)使自己與特殊事件同步。不使用操作系統(tǒng)支持的線程同步技術(shù),會(huì)產(chǎn)生許多問(wèn)題,比如:分配不必要的CPU時(shí)間,浪費(fèi);在高低優(yōu)先級(jí)線程間,若低線程負(fù)責(zé)信號(hào)重置任務(wù),則可能永遠(yuǎn)無(wú)法執(zhí)行重置。
1.2 臨界區(qū)
1.2.1 概述
臨界區(qū):在所有同步對(duì)象中,臨界區(qū)是最容易使用的,但它只能用于同步單個(gè)進(jìn)程中的線程。臨界區(qū)一次只允許一個(gè)線程取得對(duì)某個(gè)數(shù)據(jù)區(qū)的訪問(wèn)權(quán)。還有,在這些同步對(duì)象中,只有臨界區(qū)不是內(nèi)核對(duì)象,它不由操作系統(tǒng)的低級(jí)部件管理,而且不能使用句柄來(lái)操縱。
1. 在進(jìn)程中創(chuàng)建一個(gè)臨界區(qū),即在進(jìn)程中分配一個(gè)CRITICAL_SECTION數(shù)據(jù)結(jié)構(gòu),該臨界區(qū)結(jié)構(gòu)的分配必須是全局的,這樣該進(jìn)程的不同線程就能訪問(wèn)它。
2. 在使用臨界區(qū)同步線程之前,必須調(diào)用InitializeCriticalSection來(lái)初始化臨界區(qū)。在釋放資源之前,只需要初始化一次。
3. VOID EnterCriticalSection:阻塞函數(shù)。The function returns when the calling thread is granted ownership。換言之,調(diào)用線程不能獲取指定臨界區(qū)的所有權(quán)時(shí),該線程將睡眠,且在被喚醒之前,系統(tǒng)不會(huì)給它分配CPU。
4. 執(zhí)行臨界區(qū)內(nèi)的任務(wù)
5. BOOL LeaveCriticalSection:非阻塞函數(shù)。將當(dāng)前線程對(duì)指定臨界區(qū)的引用計(jì)數(shù)減壹;在使用計(jì)數(shù)變?yōu)榱銜r(shí),另一等待此臨界區(qū)的一個(gè)線程將被喚醒。
6. 當(dāng)不需要再使用該臨界區(qū)時(shí),使用DeleteCriticalSection來(lái)釋放臨界區(qū)需要的資源。此函數(shù)執(zhí)行后,再也不能使用EnterCriticalSection和LeaveCriticalSection,除非再次使用InitializeCriticalSection初始化了該臨界區(qū)。
1.2.2 注意事項(xiàng):
1. 臨界區(qū)一次只允許一個(gè)線程訪問(wèn),每個(gè)線程必須在視圖操作臨界區(qū)域數(shù)據(jù)之前調(diào)用該臨界區(qū)域標(biāo)志(即一個(gè)CRITICAL_SECTION全局變量)EnterCriticalSection后,其它想要獲得訪問(wèn)權(quán)的線程都會(huì)置于睡眠狀態(tài),且在被喚醒以前,系統(tǒng)將停止為它們分配CPU時(shí)間片。換言之,臨界區(qū)可以且僅可被一個(gè)線程擁有,當(dāng)然,沒(méi)有任何線程調(diào)用EnterCriticalSection或TryEnterCriticalSection時(shí),臨界區(qū)不屬于任何一個(gè)線程。
2. 當(dāng)擁有臨界區(qū)所有權(quán)的線程調(diào)用LeaveCriticalSection放棄所有權(quán)時(shí),系統(tǒng)只喚醒正等待中的一個(gè)線程,給它所有權(quán),其它線程則繼續(xù)睡眠。
3. 注意,擁有該臨界區(qū)的線程,每一次針對(duì)此臨界區(qū)的EnterCriticalSection調(diào)用都會(huì)成功(這里指的是重復(fù)調(diào)用也會(huì)立即返回),且會(huì)使得臨界區(qū)標(biāo)志(即一個(gè)CRITICAL_SECTION全局變量)的引用計(jì)數(shù)增壹。在另一個(gè)線程能夠擁有該臨界區(qū)之前,擁有它的線程必須調(diào)用LeaveCriticalSection足夠多次,在引用計(jì)數(shù)降為零后,另一線程才有可能擁有該臨界區(qū)。換言之,在一個(gè)正常使用臨界區(qū)的線程中,calSection和LeaveCriticalSection應(yīng)該成對(duì)使用。
1.3 用內(nèi)核對(duì)象同步線程
1.3.1 概述
臨界區(qū)非常適合于序列化對(duì)一個(gè)進(jìn)程中的數(shù)據(jù)的訪問(wèn),因?yàn)樗鼈兊乃俣群芸?。但我們或許想要使一些應(yīng)用程序與計(jì)算機(jī)中發(fā)生的其它特殊事件或者其它進(jìn)程中執(zhí)行的操作取得同步。這時(shí)臨界區(qū)無(wú)能為力。就需要使用內(nèi)核對(duì)象來(lái)同步。
下列內(nèi)核對(duì)象可用來(lái)同步線程:
1. 進(jìn)程,Processes
2. 線程,Threads
3. 文件,F(xiàn)iles
4. 控制臺(tái)輸入,Console input
5. 文件變化通知,F(xiàn)ile change notifications
6. 互斥量,Mutexes
7. 信號(hào)量,Semaphores
8. 事件(自動(dòng)重設(shè)事件和手動(dòng)重設(shè)事件),Events
9. 可等的計(jì)時(shí)器(只用于Window NT4或更高),Waitable timers
10. Jobs
每一個(gè)上面這些類型的對(duì)象都可以處于兩種狀態(tài)之一:有信號(hào)(signaled)和無(wú)信號(hào)(nonsignaled)。比如進(jìn)程和線程在終結(jié)時(shí)其內(nèi)核對(duì)象變?yōu)橛行盘?hào),而在它們處于創(chuàng)建和正在運(yùn)行時(shí),其內(nèi)核對(duì)象是無(wú)信號(hào)的。
1.3.2 內(nèi)核對(duì)象同步應(yīng)用
1. 某線程獲得某進(jìn)程的內(nèi)核對(duì)象句柄時(shí),它可以:改變進(jìn)程優(yōu)先級(jí)、獲得進(jìn)程的退出碼;使本線程與某進(jìn)程的終結(jié)取得同步等等。
2. 當(dāng)獲得某線程的內(nèi)核對(duì)象句柄時(shí),它可以:改變?cè)摼€程運(yùn)行狀態(tài)、與該線程的終結(jié)取得同步等等。
3. 當(dāng)獲得文件句柄時(shí),也可以:本線程可與某一個(gè)異步文件的I/O操作獲得同步等等。
4. 控制臺(tái)輸入對(duì)象可用來(lái)使線程在有輸入進(jìn)入時(shí)被喚醒以執(zhí)行相關(guān)任務(wù)等等。
5. 其它內(nèi)核對(duì)象―――文件改變通知、互斥量、信號(hào)量、事件、可等計(jì)時(shí)器等―――都只是為了同步對(duì)象而存在。相應(yīng)的,也有WIN32函數(shù)來(lái)創(chuàng)建、打開、關(guān)閉這些對(duì)象,將線程與這些對(duì)象同步。對(duì)這些對(duì)象,沒(méi)有其它操作可以執(zhí)行了。
1.3.3 互斥量獨(dú)有的特性(另參附錄的實(shí)驗(yàn))
互斥量對(duì)象與所有其它內(nèi)核對(duì)象的不同之處在于它是被線程所擁有的。其它所有同步對(duì)象要么有信號(hào),要么無(wú)信號(hào),僅此而已。而互斥量對(duì)象除了記錄當(dāng)前信號(hào)狀態(tài)外,還要記住此時(shí)那個(gè)線程擁有它。如果一個(gè)線程在得到一個(gè)互斥量對(duì)象(即將其置為無(wú)信號(hào)態(tài))后就終結(jié)了,互斥量也就廢棄了。在這種情況了,互斥量將永遠(yuǎn)保持無(wú)信號(hào)態(tài),因?yàn)闆](méi)有其它線程能夠通過(guò)調(diào)用ReleaseMutex來(lái)釋放它。
系統(tǒng)發(fā)現(xiàn)產(chǎn)生這種情況時(shí),就自動(dòng)將互斥量設(shè)回有信號(hào)狀態(tài)。其它等待該信號(hào)量的線程就會(huì)被喚醒,但函數(shù)的返回值為WAIT_ABANDONED而不是正常的WAIT_OBJECT_0。這時(shí),其它線程可以知道互斥量是不是被正常釋放。
其它的,互斥量與CRITICAL_SECTION類似。擁有該互斥量的線程,每次調(diào)用WaitForSingleObject都會(huì)立即成功返回,但互斥量的使用計(jì)數(shù)將增加,同樣的,也要多次調(diào)用ReleaseMutex以使引用計(jì)數(shù)變?yōu)榱?,方可供別的線程使用。
1.3.3.1 疑問(wèn)
問(wèn):其它內(nèi)核對(duì)象在線程異常終止沒(méi)有釋放所有權(quán)時(shí),系統(tǒng)回重置其狀態(tài)嗎?如果重置,將沒(méi)有任何標(biāo)記,與正常釋放無(wú)異,即不會(huì)擁有互斥量的這個(gè)返回WAIT_ABANDONED的特性?
【注意:線程擁有某個(gè)內(nèi)核對(duì)象和線程擁有某個(gè)內(nèi)核對(duì)象的所有權(quán),這二者是不同的。當(dāng)說(shuō)線程擁有某個(gè)內(nèi)核對(duì)象時(shí),要強(qiáng)調(diào)的是當(dāng)該線程終止時(shí),若線程正好擁有該內(nèi)核對(duì)象的訪問(wèn)權(quán),內(nèi)核對(duì)象也將被廢棄―――因?yàn)椴荒苤刂闷湫盘?hào)狀態(tài);而線程擁有某一個(gè)內(nèi)核對(duì)象的所用權(quán),指的是線程可以調(diào)用某些函數(shù),訪問(wèn)該內(nèi)核對(duì)象或?qū)υ搩?nèi)核對(duì)象執(zhí)行某些操作】
答:見(jiàn)附錄中后面的“討論與實(shí)驗(yàn)一”。
1.3.4 WaitForSingleObject與WaitForMultipleObjects
線程主要使用兩個(gè)函數(shù)將它們?cè)O(shè)為睡眠來(lái)等待內(nèi)核對(duì)象變?yōu)?strong>有信號(hào):即都是阻塞函數(shù)。
DWORD WaitForSingleObject(
HANDLE hHandle,
DWORD dwMilliseconds
);
DWORD WaitForMultipleObjects(
DWORD nCount,
const HANDLE* lpHandles,
BOOL bWaitAll,
DWORD dwMilliseconds
);
WaitForSingleObject,在一個(gè)指定時(shí)間(dwMilliseconds)內(nèi)等待某一個(gè)內(nèi)核對(duì)象變?yōu)橛行盘?hào),在此時(shí)間內(nèi),若等待的內(nèi)核對(duì)象一直是無(wú)信號(hào)的,則調(diào)用線程將睡眠,否則繼續(xù)執(zhí)行。超過(guò)此時(shí)間后,線程繼續(xù)運(yùn)行。函數(shù)返回值可能為:WAIT_OBJECT_0、WAIT_TIMEOUT、WAIT_ABANDONED(僅當(dāng)內(nèi)核對(duì)象為互斥量時(shí))、WAIT_FAILED。
WaitForMultipleObjects與WaitForSingleObject類似,只是它要么等待指定列表(由lpHandles指定)中若干個(gè)對(duì)象(由nCount決定)都變?yōu)橛行盘?hào),要么等待一個(gè)列表(由lpHandles指定)中的某一個(gè)對(duì)象變?yōu)橛行盘?hào)(由bWaitAll決定)。
WaitForSingleObject和WaitForMultipleObjects函數(shù)對(duì)特定的內(nèi)核對(duì)象有重要的副作用―――即它們根據(jù)不同的內(nèi)核對(duì)象,會(huì)決定是否改變內(nèi)核對(duì)象的信號(hào)狀態(tài),并執(zhí)行這種改變;這些副作用,決定了是讓等待該內(nèi)核對(duì)象的進(jìn)程或線程中的某一個(gè)被喚醒還是全都被喚醒。
1、 對(duì)進(jìn)程和線程內(nèi)核對(duì)象,這兩個(gè)函數(shù)不產(chǎn)生副作用。即,在進(jìn)程或線程內(nèi)核對(duì)象變?yōu)橛行盘?hào)后,它們將保持有信號(hào),這兩個(gè)函數(shù)不會(huì)試圖改變內(nèi)核對(duì)象的信號(hào)狀態(tài)。這樣,所有等待這些內(nèi)核對(duì)象的線程都會(huì)被喚醒。
The WaitForSingleObject function checks the current state of the specified object. If the object's state is nonsignaled, the calling thread enters the wait state. It uses no processor time while waiting for the object state to become signaled or the time-out interval to elapse.
The function modifies the state of some types of synchronization objects. Modification occurs only for the object whose signaled state caused the function to return. For example, the count of a semaphore object is decreased by one.
2、 對(duì)于互斥量、自動(dòng)重置事件和自動(dòng)重置可等的計(jì)時(shí)器對(duì)象,這兩個(gè)函數(shù)將把它們的狀態(tài)改為無(wú)信號(hào)。換言之,一旦這些對(duì)象變?yōu)橛行盘?hào)并且有一個(gè)線程被喚醒,則對(duì)象重被置為無(wú)信號(hào)狀態(tài)。于是,只有一個(gè)正在等待的線程醒來(lái),其它等待的線程將繼續(xù)睡眠。
3、 對(duì)于WaitForMultipleObjects函數(shù)還有非常重要的一個(gè)特性:當(dāng)調(diào)用它時(shí)傳遞的bWaitAll為TRUE時(shí),在所有被等待的對(duì)象都變?yōu)橛行盘?hào)之前,被等待的任何可以被改變狀態(tài)的內(nèi)核對(duì)象都不被重置為無(wú)信號(hào)狀態(tài)。換言之,在傳入?yún)?shù)bWaitAll為TRUE,WaitForMultipleObjects除非能取得所有指定對(duì)象(由lpHandles指定)的所有權(quán),它不會(huì)取得單個(gè)對(duì)象的所有權(quán)(不能取得所有權(quán),自然也不會(huì)改變此對(duì)象的信號(hào)狀態(tài))。這是為了防止死鎖。換言之,在bWaitAll為TRUE時(shí),WaitForMultipleObjects不會(huì)在沒(méi)有獲得所有被等對(duì)象所有權(quán)的情形下改變某一可以被改變狀態(tài)的內(nèi)核對(duì)象的信號(hào)狀態(tài),任何以同樣方式等待的線程都不會(huì)被喚醒―――但以其它方式等待的線程將被喚醒。
The WaitForMultipleObjects function determines whether the wait criteria have been met. If the criteria have not been met, the calling thread enters the wait state. It uses no processor time while waiting for the criteria to be met.
When bWaitAll is TRUE, the function's wait operation is completed only when the states of all objects have been set to signaled. The function does not modify the states of the specified objects until the states of all objects have been set to signaled. For example, a mutex can be signaled, but the thread does not get ownership until the states of the other objects are also set to signaled. In the meantime, some other thread may get ownership of the mutex, thereby setting its state to nonsignaled.
The function modifies the state of some types of synchronization objects. Modification occurs only for the object or objects whose signaled state caused the function to return. For example, the count of a semaphore object is decreased by one. When bWaitAll is FALSE, and multiple objects are in the signaled state, the function chooses one of the objects to satisfy the wait(到底選擇哪一個(gè)呢?天知道!); the states of the objects not selected are unaffected.
1.3.5 事件或定時(shí)器的自動(dòng)重置與手動(dòng)重置
1. 自動(dòng)重置:在內(nèi)核對(duì)象變?yōu)橛行盘?hào)時(shí),僅有一個(gè)線程可以獲得它,該線程一旦獲得,內(nèi)核對(duì)象又將變?yōu)闊o(wú)信號(hào)態(tài),其它等待的線程將繼續(xù)睡眠。由Wait類函數(shù)實(shí)現(xiàn)自動(dòng)重置未無(wú)信號(hào)狀態(tài)的功能。
2. 手動(dòng)重置:一般來(lái)說(shuō),所有等待該信號(hào)的線程都會(huì)蘇醒過(guò)來(lái)。在你調(diào)用相關(guān)函數(shù)將內(nèi)核對(duì)象置為無(wú)信號(hào)狀態(tài)前,內(nèi)核對(duì)象將一直處于信號(hào)狀態(tài)。
2 附錄
2.1 討論與實(shí)驗(yàn)一:內(nèi)核對(duì)象處于非信號(hào)狀態(tài)時(shí),相關(guān)線程結(jié)束時(shí)內(nèi)核對(duì)象是否被系統(tǒng)重置為信號(hào)臺(tái)?
互斥量被某一線程擁有,若線程退出但未釋放相應(yīng)互斥量,操作系統(tǒng)將調(diào)用ReleaseMutex釋放相應(yīng)互斥量。對(duì)于信號(hào)量和事件呢?若沒(méi)有被正確釋放或重置,操作系統(tǒng)是否在進(jìn)程結(jié)束后嘗試像對(duì)互斥量進(jìn)行釋放的操作?――若不,那么,對(duì)沒(méi)有正確釋放的信號(hào)量和事件,在操作系統(tǒng)的本次運(yùn)行期間將一直存在,是么?:舉例來(lái)說(shuō),若進(jìn)程使用某一事件來(lái)完成唯一實(shí)例,若進(jìn)程退出后沒(méi)有正確釋放相應(yīng)事件,那么,在系統(tǒng)重新啟動(dòng)之前,進(jìn)程將不能運(yùn)行。是么?
注意,對(duì)于內(nèi)核對(duì)象來(lái)說(shuō),若其引用計(jì)數(shù)變?yōu)?,系統(tǒng)將銷毀該內(nèi)核對(duì)象。為了比較,我以Event和Mutex分別構(gòu)造幾個(gè)應(yīng)用程序。(注意,Mutex是屬于線程的,但這里的應(yīng)用程序都是單線程的,換言之,這里沒(méi)有測(cè)試到進(jìn)程內(nèi)某一擁有互斥量的線程不釋放互斥量便退出的情況?。?/div>
2.1.1 Event程序
使用Event的應(yīng)用程序有四。Event創(chuàng)建時(shí)置為手動(dòng)重置事件,初始狀態(tài)為有信號(hào)狀態(tài),換言之,以::CreateEvent(NULL, TRUE, TRUE, "KernelObjectsEvent ")方式創(chuàng)建。還有,以WaitForSingleObject(內(nèi)核對(duì)象句柄,0)方式等待“KernelObjectsEvent”名的Event對(duì)象。
1. Event_OnlyReferences~僅僅嘗試用CreateEvent獲取Event句柄,不等待該Event,也不改變它的任何狀態(tài)。
2. Event_AfterWaitnonSignaled~同樣方式調(diào)用CreateEvent,然后等待,成功后置為無(wú)信號(hào)態(tài)。應(yīng)用程序繼續(xù)運(yùn)行。
3. Event_setEventBeforeWaitAfternonSignaled~同樣方式調(diào)用CreateEvent,但在等待前置事件為信號(hào)臺(tái),然后等待,成功后置為無(wú)信號(hào)態(tài)。
4. Event_setEventBeforeWaitAfterSignaled~同樣方式調(diào)用CreateEvent,但在等待前置事件為信號(hào)臺(tái),然后等待,成功后置為有信號(hào)態(tài)。
2.1.2 Mutex程序
使用Mutex的應(yīng)用程序有四。Mutex創(chuàng)建時(shí)置為非進(jìn)程擁有,換言之,以CreateMutex(NULL, FALSE, "KernelObjectsMutex")方式創(chuàng)建。還有,以WaitForSingleObject(內(nèi)核對(duì)象句柄,0)方式等待“KernelObjectsMutex”名的Mutex對(duì)象
1. Mutex_OnlyReferences~僅僅嘗試用CreateMutex獲取Mutex句柄,不等待該Mutex,也不會(huì)嘗試釋放它。
2. Mutex_AfternonSignaled~同樣方式調(diào)用CreateMutex,然后等待,成功后并不嘗試釋放它。應(yīng)用程序繼續(xù)運(yùn)行。
3. Mutex_ReleaseBeforeWaitAfternonSignaled~同樣方式調(diào)用CreateMutex,但在等待前嘗試多次調(diào)用ReleaseMutex釋放它,然后等待,成功后并不嘗試釋放它。
4. Mutex_ReleaseBeforeWaitAfterSignaled~同樣方式調(diào)用CreateMutex,但在等待前嘗試多次調(diào)用ReleaseMutex釋放它,然后等待,成功后置再次釋放它。
2.1.3 實(shí)驗(yàn)一
2.1.3.1 Event
1. Event_OnlyReferences……運(yùn)行成功,別終止程序。
2. 第一次運(yùn)行Event_AfterWaitnonSignaled……運(yùn)行成功,別終止程序。
3. 第二次運(yùn)行Event_AfterWaitnonSignaled……運(yùn)行不成功,程序退出。
4. Event_setEventBeforeWaitAfternonSignaled……運(yùn)行成功,別終止程序。
5. 第三次運(yùn)行Event_AfterWaitnonSignaled……運(yùn)行不成功,程序退出。
6. Event_setEventBeforeWaitAfterSignaled……運(yùn)行成功,別終止程序。
7. 第四次運(yùn)行Event_AfterWaitnonSignaled……運(yùn)行成功,別終止程序。
2.1.3.2 Mutex
1. Mutex_OnlyReferences……運(yùn)行成功,別終止程序。
2. 第一次運(yùn)行Mutex_AfternonSignaled……運(yùn)行成功,別終止程序。
3. 第二次運(yùn)行Mutex_AfternonSignaled……運(yùn)行不成功,程序退出。
4. Mutex_ReleaseBeforeWaitAfternonSignaled……運(yùn)行不成功,程序退出。
5. 第三次運(yùn)行Mutex_AfternonSignaled……運(yùn)行不成功,程序退出。
6. Mutex_ReleaseBeforeWaitAfterSignaled……運(yùn)行不成功,程序退出。
7. 第三次運(yùn)行Mutex_AfternonSignaled……運(yùn)行不成功,程序退出。
2.1.3.3 結(jié)論
1. 只有當(dāng)前擁有Mutex的線程調(diào)用ReleaseMutex函數(shù)才會(huì)返回TRUE,并且才會(huì)釋放該Mutex;不擁有該Mutex的線程調(diào)用ReleaseMutex函數(shù)就是簡(jiǎn)單的返回FALSE。
2. 而Mutex并不屬于某一個(gè)線程擁有,它屬于操作系統(tǒng),不關(guān)當(dāng)前事件是有信號(hào)還是無(wú)信號(hào),你都能調(diào)用SetEvent或ResetEvent改變其狀態(tài)。―――換言之,如果你在你的應(yīng)用程序中任意一處沒(méi)有正確的按照規(guī)則調(diào)用SetEvent或ResetEvent,你將達(dá)不到同步或互斥的目的。
3.
【注意:一般來(lái)說(shuō),都是利
用Event來(lái)進(jìn)行同步,而不是我們這里的讓它來(lái)達(dá)到互斥;而作為
互斥的
與線程無(wú)關(guān)的內(nèi)核對(duì)象應(yīng)該是Semaphore;而作為
互斥的
與線程有關(guān)的內(nèi)核對(duì)象應(yīng)該是Mutex?!?/div>
2.1.4 實(shí)驗(yàn)二
2.1.4.1 Event
1. 運(yùn)行Event_OnlyReferences……運(yùn)行成功,別終止程序。
2. 第一次運(yùn)行Event_AfterWaitnonSignaled……運(yùn)行成功,別終止程序。
3. 運(yùn)行Event_setEventBeforeWaitAfternonSignaled……運(yùn)行成功,別終止程序。
4. 除了第一次運(yùn)行的Mutex_OnlyReferences外,關(guān)閉所有其它應(yīng)用程序。
5. 第二次運(yùn)行Event_AfterWaitnonSignaled……運(yùn)行不成功,程序退出。
6. 運(yùn)行Event_setEventBeforeWaitAfterSignaled……運(yùn)行成功,別終止程序。
7. 除了第一運(yùn)行的Event_OnlyReferences外,關(guān)閉所有其它程序。
8. 第三次運(yùn)行Event_AfterWaitnonSignaled程序……運(yùn)行成功,別終止程序。
2.1.4.2 Mutex
1. 運(yùn)行Mutex_OnlyReferences……運(yùn)行成功,別終止程序。
2. 第一次運(yùn)行Mutex_AfternonSignaled……運(yùn)行成功,別終止程序。
3. 運(yùn)行Mutex_ReleaseBeforeWaitAfternonSignaled……運(yùn)行不成功,程序退出。
4. 除了第一次運(yùn)行的Mutex_OnlyReferences外,關(guān)閉所有其它應(yīng)用程序。
5. 第二次運(yùn)行Mutex_AfternonSignaled……捕捉到WAIT_ABANDONED信號(hào),這里我們讓程序繼續(xù)運(yùn)行。別中止程序。
6. 運(yùn)行Mutex_ReleaseBeforeWaitAfterSignaled……運(yùn)行不成功,程序退出。
7. 除了第一次運(yùn)行的Mutex_OnlyReferences外,關(guān)閉所有其它應(yīng)用程序。
8. 第三次運(yùn)行Mutex_AfternonSignaled……運(yùn)行成功,別終止程序。
2.1.4.3 結(jié)論
1. Event處于無(wú)信號(hào)狀態(tài)時(shí),相關(guān)線程或進(jìn)程退出,系統(tǒng)并不會(huì)嘗試為你將其置為有信號(hào)狀態(tài)―――所以Event實(shí)驗(yàn)中第5步運(yùn)行不成功。但由于它(這里的它是內(nèi)核對(duì)象,而不是內(nèi)核對(duì)象的句柄)不屬于任何進(jìn)程或線程,你可以再任何別的程序中重新將它置為信號(hào)臺(tái),所以第6步執(zhí)行成功。
2. Mutex處于無(wú)信號(hào)狀態(tài)時(shí),當(dāng)前擁有它的線程或進(jìn)程退出,系統(tǒng)會(huì)嘗試將其置為有信號(hào)狀態(tài)―――所以Mutex實(shí)驗(yàn)中第5步運(yùn)行成功,但捕捉到WAIT_ABANDONED信號(hào),它指明是操作系統(tǒng)為你重置為有信號(hào)狀態(tài)的。同樣,由于某一線程現(xiàn)在擁有它,它未釋放該互斥量且線程未退出時(shí),它屬于這個(gè)線程,你不能剝奪它的權(quán)利,所以第6步運(yùn)行不成功。
本站僅提供存儲(chǔ)服務(wù),所有內(nèi)容均由用戶發(fā)布,如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請(qǐng)
點(diǎn)擊舉報(bào)。