转— 秒杀八线程第⑩篇 经典线程同步 互斥量Mutex

读书本篇在此之前推荐阅读以下姊妹篇:

秒杀三十二线程第6篇三个经文的八线程同步问题

秒杀二十二十四线程第4篇经典线程同步关键段CS

秒杀二十多线程第5篇经典线程同步事件伊夫nt

 

前边介绍了关键段CS事件Event经典线程同步难点中的使用。本篇介绍用互斥量Mutex来缓解那么些题材。

互斥量也是三个水源对象,它用来保管一个线程独占3个能源的造访。互斥量与重点段的行为丰富相似,并且互斥量能够用来分裂进程中的线程互斥访问能源。使用互斥量Mutex首要将用到三个函数。下边是那些函数的原型和行使表明。

第一个 CreateMutex

函数作用:创造互斥量(注意与事件伊夫nt的创办函数相比)

函数原型:

HANDLECreateMutex(

  LPSECURITY_ATTRIBUTESlpMutexAttributes,

  BOOLbInitialOwner,     

  LPCTSTRlpName

);

函数说明:

第一个参数表示安全控制,一般直接传入NULL。

其次个参数用来规定互斥量的发端拥有者。假如传入TRUE表示互斥量对象内部会记录创制它的线程的线程ID号并将递归计数设置为1,由于该线程ID非零,所以互斥量处于未触及状态。假设传入FALSE,那么互斥量对象内部的线程ID号将安装为NULL,递归计数设置为0,那象征互斥量不为任何线程占用,处于触发状态。

其八个参数用来安装互斥量的称呼,在多少个经过中的线程正是经过名称来担保它们访问的是同2个互斥量。

函数访问值:

水到渠成重临多少个代表互斥量的句柄,战败再次来到NULL。

 

第三个打开互斥量

函数原型:

HANDLEOpenMutex(

 DWORDdwDesiredAccess,

 BOOLbInheritHandle,

 LPCTSTRlpName    
//名称

);

函数表达:

先是个参数表示访问权限,对互斥量一般传入MUTEX_ALL_ACCESS。详细表达能够查阅MSDN文书档案。

第叁个参数表示互斥量句柄继承性,一般传入TRUE即可。

其两个参数表示名称。某一个进程中的线程创制互斥量后,其它进度中的线程就足以经过这些函数来找到这么些互斥量。

函数访问值:

打响再次来到3个意味互斥量的句柄,失利再次回到NULL。

 

其四个触发互斥量

函数原型:

BOOLReleaseMutex (HANDLEhMutex)

函数表明:

访问互斥财富前应当要调用等待函数,停止访问时就要调用ReleaseMutex()来代表友好已经落成访问,其它线程能够起来走访了。

 

说到底二个清理互斥量

鉴于互斥量是根本对象,由此使用CloseHandle()就能够(这或多或少享有内核对象都一模一样)。

 

接下去大家就在经典二十四线程难点用互斥量来保管主线程与子线程之间的同台,由于互斥量的应用函数类似于事件伊夫nt,所以能够效仿上一篇的贯彻来写出代码:

[cpp] view
plain
copy

  1. //经典线程同步难题 互斥量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. //互斥量与根本段  
  10. HANDLE  g_hThreadParameter;  
  11. CRITICAL_SECTION g_csThreadCode;  
  12.   
  13. int main()  
  14. {  
  15.     printf(”     经典线程同步 互斥量Mutex\n”);  
  16.     printf(” — by MoreWindows( http://blog.csdn.net/MoreWindows ) –\n\n”);  
  17.       
  18.     //开首化互斥量与根本段 第1个参数为TRUE表示互斥量为创设线程全体  
  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); //等待互斥量被触发  
  29.         i++;  
  30.     }  
  31.     WaitForMultipleObjects(THREAD_NUM, handle, TRUE, INFINITE);  
  32.       
  33.     //销毁互斥量和根本段  
  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);//触发互斥量  
  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(“线程编号为%d  全局财富值为%d\n”, nThreadNum, g_nNum);  
  51.     LeaveCriticalSection(&g_csThreadCode);  
  52.     return 0;  
  53. }  

运作结果如下图:

图片 1

能够看看,与重点段类似,互斥量也是不能够缓解线程间的共同难题。

       联想到根本段会记录线程ID即有“线程拥有权”的,而互斥量也记录线程ID,莫非它也有“线程拥有权”这一说法。

       答案真的如此,互斥量也是有“线程拥有权”概念的。“线程拥有权”在关键段中有详细的认证,那里就不再赘言了。其余由于互斥量常用来多进度之间的线程互斥,所以它比第叁段还多一个很有用的特征——“遗弃”情状的拍卖。比如有一个占据互斥量的线程在调用ReleaseMutex()触
发互斥量前就意外终止了(也便是该互斥量被“放弃”了),那么全体等待这些互斥量的线程是或不是会由于该互斥量不可能被触发而陷入二个不辍等待历程中了?那鲜明不客观。因为占用有个别互斥量的线程既然终止了那能够验证它不再利用被该互斥量爱抚的能源,所以这么些能源完全并且应当被其它线程来利用。由此在那种“遗弃”意况下,系统活动把该互斥量内部的线程ID设置为0,并将它的递归计数器复置为0,表示那些互斥量被触发了。然后系统将“公平地”选定1个等候线程来实现调度(被选中的线程的WaitForSingleObject()会回到WAIT_ABANDONED_0)。

 

上面写一个程序来表达下:

第①个程序成立互斥量并等候用户输入后就接触互斥量。第二个程序先开辟互斥量,成功后就等候并遵照等待结果作相应的出口。详见代码:

首先个程序:

[cpp] view
plain
copy

  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); //成立互斥量  
  8.     printf(“互斥量已经创办,将来按任意键触发互斥量\n”);  
  9.     getch();  
  10.     //exit(0);  
  11.     ReleaseMutex(hMutex);  
  12.     printf(“互斥量已经接触\n”);  
  13.     CloseHandle(hMutex);  
  14.     return 0;  
  15. }  

第三个程序:

[cpp] view
plain
copy

  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); //打开互斥量  
  7.     if (hMutex == NULL)  
  8.     {  
  9.         printf(“打开互斥量失利\n”);  
  10.         return 0;  
  11.     }  
  12.     printf(“等待中….\n”);  
  13.     DWORD dwResult = WaitForSingleObject(hMutex, 20 * 一千); //等待互斥量被触发  
  14.     switch (dwResult)  
  15.     {  
  16.     case WAIT_ABANDONED:  
  17.         printf(“拥有互斥量的历程意外终止\n”);  
  18.         break;  
  19.   
  20.     case WAIT_OBJECT_0:  
  21.         printf(“已经收取信号\n”);  
  22.         break;  
  23.   
  24.     case WAIT_TIMEOUT:  
  25.         printf(“信号未在显明的日子内送到\n”);  
  26.         break;  
  27.     }  
  28.     CloseHandle(hMutex);  
  29.     return 0;  
  30. }  

使用那2个程序时要先运行程序往往运维程序二。上边体现部分输出结果:

结果一.三个进度顺遂进行达成:

图片 2

结果二.将顺序一中//exit(0);前面包车型地铁注释符号去掉,那样程序一在触发互斥量此前就会因为执行exit(0);语句而且脱离,程序二会吸收接纳WAIT_ABANDONED音信并出口“拥有互斥量的进程意外终止”:

图片 3

有这一个对“遗弃”难题的拍卖,在多进度中的线程同步也可以放心的施用互斥量。

 

末段总括下互斥量Mutex:

1.互斥量是根本对象,它与第②段都有“线程全体权”所以不可能用于线程的同台。

2.互斥量能够用于八个经过之间线程互斥难题,并且能健全的缓解某经过意外终止所造成的“吐弃”难题。

相关文章