小男孩‘自慰网亚洲一区二区,亚洲一级在线播放毛片,亚洲中文字幕av每天更新,黄aⅴ永久免费无码,91成人午夜在线精品,色网站免费在线观看,亚洲欧洲wwwww在线观看

分享

秒殺多線程第七篇 經(jīng)典線程同步 互斥量Mutex

 Fredanf 2012-08-30
 

秒殺多線程第七篇 經(jīng)典線程同步 互斥量Mutex

分類(lèi): Windows多線程 Windows編程 15519人閱讀 評(píng)論(49) 收藏 舉報(bào)

閱讀本篇之前推薦閱讀以下姊妹篇:

秒殺多線程第四篇一個(gè)經(jīng)典的多線程同步問(wèn)題

秒殺多線程第五篇經(jīng)典線程同步關(guān)鍵段CS

秒殺多線程第六篇經(jīng)典線程同步事件Event

 

前面介紹了關(guān)鍵段CS、事件Event經(jīng)典線程同步問(wèn)題中的使用。本篇介紹用互斥量Mutex來(lái)解決這個(gè)問(wèn)題。

互斥量也是一個(gè)內(nèi)核對(duì)象,它用來(lái)確保一個(gè)線程獨(dú)占一個(gè)資源的訪問(wèn)?;コ饬颗c關(guān)鍵段的行為非常相似,并且互斥量可以用于不同進(jìn)程中的線程互斥訪問(wè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)程中的線程就是通過(guò)名稱來(lái)確保它們?cè)L問(wèn)的是同一個(gè)互斥量。

函數(shù)訪問(wèn)值:

成功返回一個(gè)表示互斥量的句柄,失敗返回NULL。

 

第二個(gè)打開(kāi)互斥量

函數(shù)原型:

HANDLEOpenMutex(

 DWORDdwDesiredAccess,

 BOOLbInheritHandle,

 LPCTSTRlpName     //名稱

);

函數(shù)說(shuō)明:

第一個(gè)參數(shù)表示訪問(wèn)權(quán)限,對(duì)互斥量一般傳入MUTEX_ALL_ACCESS。詳細(xì)解釋可以查看MSDN文檔。

第二個(gè)參數(shù)表示互斥量句柄繼承性,一般傳入TRUE即可。

第三個(gè)參數(shù)表示名稱。某一個(gè)進(jìn)程中的線程創(chuàng)建互斥量后,其它進(jìn)程中的線程就可以通過(guò)這個(gè)函數(shù)來(lái)找到這個(gè)互斥量。

函數(shù)訪問(wèn)值:

成功返回一個(gè)表示互斥量的句柄,失敗返回NULL。

 

第三個(gè)觸發(fā)互斥量

函數(shù)原型:

BOOLReleaseMutex (HANDLEhMutex)

函數(shù)說(shuō)明:

訪問(wèn)互斥資源前應(yīng)該要調(diào)用等待函數(shù),結(jié)束訪問(wèn)時(shí)就要調(diào)用ReleaseMutex()來(lái)表示自己已經(jīng)結(jié)束訪問(wèn),其它線程可以開(kāi)始訪問(wèn)了。

 

最后一個(gè)清理互斥量

由于互斥量是內(nèi)核對(duì)象,因此使用CloseHandle()就可以(這一點(diǎn)所有內(nèi)核對(duì)象都一樣)。

 

接下來(lái)我們就在經(jīng)典多線程問(wèn)題用互斥量來(lái)保證主線程與子線程之間的同步,由于互斥量的使用函數(shù)類(lèi)似于事件Event,所以可以仿照上一篇的實(shí)現(xiàn)來(lái)寫(xiě)出代碼

  1. //經(jīng)典線程同步問(wèn)題 互斥量Mutex  
  2. #include <stdio.h>  
  3. #include <process.h>  
  4. #include <windows.h>  
  5.   
  6. long g_nNum;  
  7. unsigned int __stdcall Fun(void *pPM);  
  8. const int THREAD_NUM = 10;  
  9. //互斥量與關(guān)鍵段  
  10. HANDLE  g_hThreadParameter;  
  11. CRITICAL_SECTION g_csThreadCode;  
  12.   
  13. int main()  
  14. {  
  15.     printf("     經(jīng)典線程同步 互斥量Mutex\n");  
  16.     printf(" -- by MoreWindows( http://blog.csdn.net/MoreWindows ) --\n\n");  
  17.       
  18.     //初始化互斥量與關(guān)鍵段 第二個(gè)參數(shù)為T(mén)RUE表示互斥量為創(chuàng)建線程所有  
  19.     g_hThreadParameter = CreateMutex(NULL, FALSE, NULL);  
  20.     InitializeCriticalSection(&g_csThreadCode);  
  21.   
  22.     HANDLE  handle[THREAD_NUM];   
  23.     g_nNum = 0;   
  24.     int i = 0;  
  25.     while (i < THREAD_NUM)   
  26.     {  
  27.         handle[i] = (HANDLE)_beginthreadex(NULL, 0, Fun, &i, 0, NULL);  
  28.         WaitForSingleObject(g_hThreadParameter, INFINITE); //等待互斥量被觸發(fā)  
  29.         i++;  
  30.     }  
  31.     WaitForMultipleObjects(THREAD_NUM, handle, TRUE, INFINITE);  
  32.       
  33.     //銷(xiāo)毀互斥量和關(guān)鍵段  
  34.     CloseHandle(g_hThreadParameter);  
  35.     DeleteCriticalSection(&g_csThreadCode);  
  36.     for (i = 0; i < THREAD_NUM; i++)  
  37.         CloseHandle(handle[i]);  
  38.     return 0;  
  39. }  
  40. unsigned int __stdcall Fun(void *pPM)  
  41. {  
  42.     int nThreadNum = *(int *)pPM;  
  43.     ReleaseMutex(g_hThreadParameter);//觸發(fā)互斥量  
  44.       
  45.     Sleep(50);//some work should to do  
  46.   
  47.     EnterCriticalSection(&g_csThreadCode);  
  48.     g_nNum++;  
  49.     Sleep(0);//some work should to do  
  50.     printf("線程編號(hào)為%d  全局資源值為%d\n", nThreadNum, g_nNum);  
  51.     LeaveCriticalSection(&g_csThreadCode);  
  52.     return 0;  
  53. }  

運(yùn)行結(jié)果如下圖:

可以看出,與關(guān)鍵段類(lèi)似,互斥量也是不能解決線程間的同步問(wè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ú)窮的等待過(guò)程中了?這顯然不合理。因?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)。

 

下面寫(xiě)二個(gè)程序來(lái)驗(yàn)證下:

第一個(gè)程序創(chuàng)建互斥量并等待用戶輸入后就觸發(fā)互斥量。第二個(gè)程序先打開(kāi)互斥量,成功后就等待并根據(jù)等待結(jié)果作相應(yīng)的輸出。詳見(jiàn)代碼:

第一個(gè)程序:

  1. #include <stdio.h>  
  2. #include <conio.h>  
  3. #include <windows.h>  
  4. const char MUTEX_NAME[] = "Mutex_MoreWindows";  
  5. int main()  
  6. {  
  7.     HANDLE hMutex = CreateMutex(NULL, TRUE, MUTEX_NAME); //創(chuàng)建互斥量  
  8.     printf("互斥量已經(jīng)創(chuàng)建,現(xiàn)在按任意鍵觸發(fā)互斥量\n");  
  9.     getch();  
  10.     //exit(0);  
  11.     ReleaseMutex(hMutex);  
  12.     printf("互斥量已經(jīng)觸發(fā)\n");  
  13.     CloseHandle(hMutex);  
  14.     return 0;  
  15. }  

第二個(gè)程序:

  1. #include <stdio.h>  
  2. #include <windows.h>  
  3. const char MUTEX_NAME[] = "Mutex_MoreWindows";  
  4. int main()  
  5. {  
  6.     HANDLE hMutex = OpenMutex(MUTEX_ALL_ACCESS, TRUE, MUTEX_NAME); //打開(kāi)互斥量  
  7.     if (hMutex == NULL)  
  8.     {  
  9.         printf("打開(kāi)互斥量失敗\n");  
  10.         return 0;  
  11.     }  
  12.     printf("等待中....\n");  
  13.     DWORD dwResult = WaitForSingleObject(hMutex, 20 * 1000); //等待互斥量被觸發(fā)  
  14.     switch (dwResult)  
  15.     {  
  16.     case WAIT_ABANDONED:  
  17.         printf("擁有互斥量的進(jìn)程意外終止\n");  
  18.         break;  
  19.   
  20.     case WAIT_OBJECT_0:  
  21.         printf("已經(jīng)收到信號(hào)\n");  
  22.         break;  
  23.   
  24.     case WAIT_TIMEOUT:  
  25.         printf("信號(hào)未在規(guī)定的時(shí)間內(nèi)送到\n");  
  26.         break;  
  27.     }  
  28.     CloseHandle(hMutex);  
  29.     return 0;  
  30. }  

運(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ì)“遺棄”問(wèn)題的處理,在多進(jìn)程中的線程同步也可以放心的使用互斥量。

 

最后總結(jié)下互斥量Mutex

1.互斥量是內(nèi)核對(duì)象,它與關(guān)鍵段都有“線程所有權(quán)”所以不能用于線程的同步。

2.互斥量能夠用于多個(gè)進(jìn)程之間線程互斥問(wèn)題,并且能完美的解決某進(jìn)程意外終止所造成的“遺棄”問(wèn)題。

 

下一篇《秒殺多線程第八篇 經(jīng)典線程同步 信號(hào)量Semaphore》將介紹使用信號(hào)量Semaphore來(lái)解決這個(gè)經(jīng)典線程同步問(wèn)題。

 

 

轉(zhuǎn)載請(qǐng)標(biāo)明出處,原文地址:http://blog.csdn.net/morewindows/article/details/7470936

如果覺(jué)得本文對(duì)您有幫助,請(qǐng)點(diǎn)擊支持一下,您的支持是我寫(xiě)作最大的動(dòng)力,謝謝。

    本站是提供個(gè)人知識(shí)管理的網(wǎng)絡(luò)存儲(chǔ)空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點(diǎn)。請(qǐng)注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購(gòu)買(mǎi)等信息,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請(qǐng)點(diǎn)擊一鍵舉報(bào)。
    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評(píng)論

    發(fā)表

    請(qǐng)遵守用戶 評(píng)論公約

    類(lèi)似文章 更多