Mutex与Event控制互斥事件的使用详解

最近写一程序,误用了Mutex的功能,错把Mutex当Event用了。

【Mutex】

使用Mutex的主要函数:CreateMutex、ReleaseMutex、OpenMutex、WaitForSingleObject、WaitForMultipleObjects。

CreateMutex:其中第二个参数是表示当前线程拥有权。

TRUE:创建线程获得初始所有权的互斥对象(即信号已被当前线程获得,没有释放前其它线程不能获得。如果当前线程调用了WaitForSingleObject   函 数, 则释放次数等于调用次数加1)。     

 FALSE:创建线程没有获得互斥对象的所有权。也就是自由争取,看谁先Wait到。 不管怎么样,MUtex的释放规则是:谁拥有谁释放,还有在线程结束时, 线程所获得的Mutex自动释放;当然还可以使用命名Mutex做唯一性验证,这个在整个windows生存期下有效。

【Event】

与Mutex不一样,Event是任何时候都是可以操作的,而且没有同调用多次WaitForSingleObject和同时释放多次一说。

它的主要操作函数有:  CreateEvent、SetEvent、WaitForSingleObject。

CreateEvent参数说明。

第二个参数表示调用WaitForSingleObject后手动(TRUE)/自动(FALSE)为无信号状态。

第三个参数表示初始状态为有(TRUE)/无(FALSE)信号。  

Event的获得是通过一个队列去排队获得的,SetEvent没有限制使用,在任何可以调用的地方都可以调用。

Mutex,的互斥是以线程为基本单位,而Event是以代码段为基本单位。所以在两者的使用上有着不同的功能用途。

https://www.cnblogs.com/upendi/archive/2013/02/25/2932154.html
事件EVENT与waitforsingleobject的使用 

事件event与waitforsingleobject的配合使用,能够解决很多同步问题,也可以在数据达到某个状态时启动另一个线程的执行,如报警。

event的几个函数:

1、CreateEvent和OpenEvent

 HANDLE WINAPI CreateEvent(
__in LPSECURITY_ATTRIBUTES lpEventAttributes, //表示安全控制,一般直接传入NULL,表示不能被子进程继承
__in BOOL bManualReset, //参数确定事件是手动置位还是自动置位,传入TRUE表示手动置位,传入FALSE表示自动置位。
__in BOOL bInitialState, //Event的初始状态, TRUE为触发,FALSE未触发
__in LPCTSTR lpName //Event object的名字,NULL表示没名字(without a name)
); 要是CreateEvent创建的事件没名字 这个函数就没啥用了,不多做介绍,可查看msn。
1 HANDLE WINAPI OpenEvent( //获得已经存在的Event的事件句柄
2 __in DWORD dwDesiredAccess,
3 __in BOOL bInheritHandle,
4 __in LPCTSTR lpName //要打开的事件名字
5 ); 2、SetEvent,触发事件 BOOL SetEvent(HANDLE hEvent); 3、ResetEvent,使事件状态设为未触发,如在创建事件时第二个参数为TRUE手动设置,则需要该函数去恢复事件为未触发状态。 BOOL SetEvent(HANDLE hEvent); 4、PulseEvent, 如在创建事件时第二个参数为TRUE手动设置,其功能相当于SetEvent()后立即调用ResetEvent()
BOOL PulseEvent(HANDLE hEvent) 也就是说在自动重置模式下PulseEvent和SetEvent的作用没有什么区别,但在手动模式下PulseEvent就有明显的不同, 可以比较容易的控制程序是单步走,还是连续走。如果让循环按要求执行一次就用PulseEvent,如果想让循环连续不停的运转就用SetEvent ,在要求停止的地方发个ResetEvent就OK了。 5、CloseHandle(),关闭该句柄。 ********** WaitForSingleObject函数。使线程处于等待状态,如等待某一事件的触发。 DWORD WINAPI WaitForSingleObject( HANDLE hHandle, //等待的触发句柄 , 如前面说的Event的句柄 DWORD dwMilliseconds //等待多长时间,单位ms 如5000 则为5s 若为INFINITE表示无限等待
);

http://www.cnblogs.com/LouMengzhao/p/6076368.html

http://blog.sina.com.cn/s/blog_6163bdeb0100qlw1.html

事件和其他量一样,也是一个内核对象。

使用事件可以进行同步,主要是可以规定先后顺序。

事件分为手动置位事件和自动置位事件,两个的关系是什么呢?

手动置位事件就是你一旦触发之后,所有的状态都被释放。

自动置位事件你触发之后,只有一个状态被释放,这个时候就有不确定性了。

如何使用事件?有这么几个函数。

第一个 CreateEvent

函数功能:创建事件

函数原型:

HANDLECreateEvent(

 LPSECURITY_ATTRIBUTESlpEventAttributes,

 BOOLbManualReset,

 BOOLbInitialState,

 LPCTSTRlpName

);

函数说明:

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

第二个参数确定事件是手动置位还是自动置位,传入TRUE表示手动置位,传入FALSE表示自动置位。如果为自动置位,
则对该事件调用WaitForSingleObject()后会自动调用ResetEvent()使事件变成未触发状态。打个小小比方,
手动置位事件相当于教室门,教室门一旦打开(被触发),所以有人都可以进入直到老师去关上教室门(事件变成未触发)。
自动置位事件就相当于医院里拍X光的房间门,门打开后只能进入一个人,这个人进去后会将门关上,其它人不能进入除非门重新被打开(事件重新被触发)。 第三个参数表示事件的初始状态,传入TRUR表示已触发。 第四个参数表示事件的名称,传入NULL表示匿名事件。 第二个 OpenEvent 函数功能:根据名称获得一个事件句柄。 函数原型: HANDLEOpenEvent( DWORDdwDesiredAccess, BOOLbInheritHandle, LPCTSTRlpName //名称 ); 函数说明: 第一个参数表示访问权限,对事件一般传入EVENT_ALL_ACCESS。详细解释可以查看MSDN文档。 第二个参数表示事件句柄继承性,一般传入TRUE即可。 第三个参数表示名称,不同进程中的各线程可以通过名称来确保它们访问同一个事件。 第三个SetEvent 函数功能:触发事件 函数原型:BOOLSetEvent(HANDLEhEvent); 函数说明:每次触发后,必有一个或多个处于等待状态下的线程变成可调度状态。 第四个ResetEvent 函数功能:将事件设为末触发 函数原型:BOOLResetEvent(HANDLEhEvent); 最后一个事件的清理与销毁 由于事件是内核对象,因此使用CloseHandle()就可以完成清理与销毁了。 关于之前的那个问题,如何来设置同步呢? 首先是初始化: ​
•//事件与关键段
•HANDLE g_hThreadEvent;
•CRITICAL_SECTION g_csThreadCode;

• //初始化事件和关键段 自动置位,初始无触发的匿名事件
• g_hThreadEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
• InitializeCriticalSection(&g_csThreadCode);
• //销毁事件和关键段
• CloseHandle(g_hThreadEvent);
• DeleteCriticalSection(&g_csThreadCode);
•​

•关键代码段修改:
•主循环当中:
• while (i < THREAD_NUM)
• {
• handle[i] = (HANDLE)_beginthreadex(NULL, 0, Fun, &i, 0, NULL);
• WaitForSingleObject(g_hThreadEvent, INFINITE); //等待事件被触发 i++;
• }
•线程函数当中:
•​
•int nThreadNum = *(int *)pPM;
• SetEvent(g_hThreadEvent); //触发事件 于是就可完成同步工作。 匿名和有名的差别: 匿名的时候具有亲缘关系的才能看到,而有名管道则可以在其他进程当中看到,这个是大部分的差别。 如果是有名的,那么create的时候,如果有名的已经存在,则返回之前的相应的句柄。​ 另外需要注意的就是注意等待的副作用,如果是自动重置,可能wait触发之后会reset. 关于函数pulseEvent 函数功能:将事件触发后立即将事件设置为未触发,相当于触发一个事件脉冲。 函数原型:BOOLPulseEvent(HANDLEhEvent); 函数说明:这是一个不常用的事件函数,此函数相当于SetEvent()后立即调用ResetEvent();此时情况可以分为两种: 1.对于手动置位事件,所有正处于等待状态下线程都变成可调度状态。 2.对于自动置位事件,所有正处于等待状态下线程只有一个变成可调度状态。 此后事件是末触发的。该函数不稳定,因为无法预知在调用PulseEvent ()时哪些线程正处于等待状态。 ​ 如何理解,可以理解为一个脉冲,只解放当时在等待的那些,而之后的就不在考虑了。 一个简答的例子解释: 触发一个事件脉冲PulseEvent ()写一个例子,主线程启动7个子线程,其中有5个线程Sleep(10)后对一事件调用等待函数(称为快线程),
另有2个线程Sleep(100)后也对该事件调用等待函数(称为慢线程)。主线程启动所有子线程后再Sleep(50)保证有5个快线程都正处于等待状态中。
此时若主线程触发一个事件脉冲,那么对于手动置位事件,这5个线程都将顺利执行下去。对于自动置位事件,这5个线程中会有中一个顺利执行下去。
而不论手动置位事件还是自动置位事件,那2个慢线程由于Sleep(100)所以会错过事件脉冲,因此慢线程都会进入等待状态而无法顺利执行下去。​ http://blog.sina.com.cn/s/blog_c33b15000102x3oa.html

最新文章

  1. 【从零开始学BPM,Day4】业务集成
  2. git review &amp; devops过程
  3. Windows 下安装使用docker swarm machine docker toolbox
  4. RPC远程过程调用协议
  5. 【python】linux将python改为默认3.4版本
  6. 精通 ASP.NET MVC 4 学习笔记(一)
  7. 一步步学习ASP.NET MVC3 (10)——@Ajax,JavaScriptResult(1)
  8. Jquery 遍历数组之grep()方法介绍
  9. 扩展SpringMVC以支持绑定JSON格式的请求参数
  10. PHP-5.5.10+Apache httpd-2.4.9在Windows系统下配置实战
  11. CSS3中字体平滑处理和抗锯齿渲染
  12. Github+Hexo,搭建专属网站
  13. Python正则表达式指南(转)
  14. webapi框架搭建-创建项目(一)
  15. TCP-IP详解笔记5
  16. bug总结
  17. Xdebug在PHP中的安装配置
  18. 第二阶段——个人工作总结DAY08
  19. Notes for building gimp-print
  20. 利用 PowerShell 分析SharePoint WebApplication 体系结构

热门文章

  1. 【转】标准C++类std::string的内存共享和Copy-On-Write技术
  2. 跟我学SharePoint 2013视频培训课程——自定义网站导航(4)
  3. mongodb MongoDB 聚合 group(转)
  4. 使用mysqltools配置读写分离环境
  5. 更改 AWS RDS mysql时区 -摘自网络
  6. MySql(十):MySQL性能调优——MySQL Server性能优化
  7. [LeetCode] Read N Characters Given Read4 I &amp; II
  8. [LeetCode] Palindrome Permutation I &amp; II
  9. [hihoCoder] 第五十二周: 连通性&#183;一
  10. 关于Suppressing notification from package com.xxx.xxx by user request.的异常