转— 秒杀多线程第七首 经典线程同步 互斥量Mutex

翻阅本篇之前推荐阅读以下姊妹篇:

《秒杀多线程第四首一个经文的多线程同步问题》

《秒杀多线程第五首经典线程同步关键段CS》

《秒杀多线程第六首经典线程同步事件Event》

 

面前介绍了关键段CS、事件Event在经线程同步问题吃之采取。本篇介绍用互斥量Mutex来化解之题目。

互斥量也是一个基础对象,它之所以来保证一个线程独占一个资源的访。互斥量与重大段的一言一行好相似,并且互斥量可以用来不同进程遭到之线程互斥访问资源。使用互斥量Mutex主要用故到四只函数。下面是这些函数的原型和动说明。

第一个 CreateMutex

函数功能:创建互斥量(注意与事件Event的缔造函数对比)

函数原型:

HANDLECreateMutex(

  LPSECURITY_ATTRIBUTESlpMutexAttributes,

  BOOLbInitialOwner,     

  LPCTSTRlpName

);

函数说明:

首先单参数表示安全控制,一般直接传入NULL。

第二单参数用来确定互斥量的开拥有者。如果传入TRUE表示互斥量对象中会记录创建它的线程的线程ID号并拿递归计数设置为1,由于该线程ID非零,所以互斥量处于无点状态。如果传入FALSE,那么互斥量对象中的线程ID号将设置也NULL,递归计数设置为0,这意味互斥量不也其它线程占用,处于触发状态。

其三个参数用来装互斥量的名称,在多单过程中之线程就是经过名称来保证其访问的凡同一个互斥量。

函数访问值:

得逞返回一个代表互斥量的句柄,失败返回NULL。

 

老二独打开互斥量

函数原型:

HANDLEOpenMutex(

 DWORDdwDesiredAccess,

 BOOLbInheritHandle,

 LPCTSTRlpName    
//名称

);

函数说明:

首先单参数表示访问权限,对互斥量一般传入MUTEX_ALL_ACCESS。详细分解好查MSDN文档。

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

老三独参数表示称。某一个历程遭到之线程创建互斥量后,其它进程被的线程就可以经过者函数来找到这互斥量。

函数访问值:

遂返回一个代表互斥量的句柄,失败返回NULL。

 

老三单点互斥量

函数原型:

BOOLReleaseMutex (HANDLEhMutex)

函数说明:

顾互斥资源前应该要是调用等待函数,结束访时将调用ReleaseMutex()来表示友好一度收访,其它线程可以起来走访了。

 

终极一个清理互斥量

由于互斥量是基本对象,因此利用CloseHandle()就足以(这或多或少颇具内核对象都一模一样)。

 

通下去我们不怕在经多线程问题用互斥量来确保主线程和子线程之间的合,由于互斥量的应用函数类似于波Event,所以可以学上同样篇之兑现来描写起代码:

[cpp] view
plaincopy

  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.     //初始化互斥量与第一段 第二个参数为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. }  

运转结果如下图:

ACCESS 1

可以看,与第一段类似,互斥量也是休克化解线程间的合问题。

       联想到第一段会记录线程ID就产生“线程拥有权”的,而互斥量也记录线程ID,莫非它吧闹“线程拥有权”这无异说法。

       答案真的这样,互斥量也是生“线程拥有权”概念的。“线程拥有权”在关键段遭逢来详尽的求证,这里就不再赘述了。另外是因为互斥量常用于多进程中的线程互斥,所以她比较第一段还多一个坏有因此底特性——“遗弃”情况的拍卖。比如有一个据为己有互斥量的线程在调用ReleaseMutex()触
发互斥量前即奇怪已了(相当给该互斥量被“遗弃”了),那么富有等待这互斥量的线程是否会面由于该互斥量无法让硌而陷入一个不辍等待过程遭到了?这显
然不成立。因为占用某个互斥量的线程既然已了那么可以验证其不再利用于拖欠互斥量保护之资源,所以这些资源全以该让外线程来用。因此当这种“遗弃”情况下,系统活动将欠互斥量内部的线程ID设置为0,并拿她的递归计数器复置为0,表示此互斥量被触发了。然后系统将“公平地”选定一个等待线程来形成调度(被入选的线程的WaitForSingleObject()会返回WAIT_ABANDONED_0)。

 

下写二独次来说明下:

率先只次创建互斥量并伺机用户输入后就是点互斥量。第二个次先打开互斥量,成功后即等候并基于等待结果作相应的出口。详见代码:

第一独程序:

[cpp] view
plaincopy

  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
plaincopy

  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 * 1000); //等待互斥量被触发  
  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. }  

利用这第二只次时如优先启动程序往往启动程序二。下面展示部分输出结果:

结果一.二单过程顺利执行了:

ACCESS 2

结果二.将先后一中//exit(0);前面的注释符号去丢,这样程序一样当接触互斥量之前即会见因执行exit(0);语句以脱离,程序二碰头接到WAIT_ABANDONED消息并出口“拥有互斥量的进程意外已”:

ACCESS 3

发出此针对“遗弃”问题之处理,在多进程被的线程同步啊得放心的运用互斥量。

 

说到底总结下互斥量Mutex:

1.互斥量是根本对象,它和重点段都产生“线程所有权”所以无克用于线程的一道。

2.互斥量能够用于多单过程中线程互斥问题,并且会完善的缓解有过程意外已所导致的“遗弃”问题。

相关文章