事件EVENT与waitforsingleobject的使用以及Mutex与Event的区别

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
原文地址:https://www.cnblogs.com/leijiangtao/p/4677664.html