C++ 经典线程同步 事件Event(九)

上一篇中使用关键段来解决经典的多线程同步互斥问题,由于“线程所有权”特性所以关键段只能用于线程的互斥而不能用于同步。本篇介绍用事件Event来尝试解决这个线程同步问题。

Event原理解析

多线程同步Event,主要用于线程间的等待通知。内核对象中,事件内核对象是个最基本的对象。它们包含一个使用计数(与所有内核对象一样),一个用于指明该事件是个自动重置的事件还是一个人工重置的事件的布尔值,另一个用于指明该事件处于已通知状态还是未通知状态的布尔值。
事件能够通知一个操作已经完成。有两种不同类型的事件对象。一种是人工重置的事件,另一种是自动重置的事件。当人工重置的事件得到通知时,等待该事件的所有线程均变为可调度线程。当一个自动重置的事件得到通知时,等待该事件的线程中只有一个线程变为可调度线程。
        当一个线程执行初始化操作,然后通知另一个线程执行剩余的操作时,事件使用得最多。事件初始化为未通知状态,然后,当该线程完成它的初始化操作后,它就将事件设置为已通知状态。这时,一直在等待该事件的另一个线程发现该事件已经得到通知,因此它就变成可调度线程。


Event API

Event function Description
CreateEvent Creates or opens a named or unnamed event object.
CreateEventEx Creates or opens a named or unnamed event object and returns a handle to the object.
OpenEvent Opens an existing named event object.
PulseEvent Sets the specified event object to the signaled state and then resets it to the nonsignaled state after releasing the appropriate number of waiting threads.
ResetEvent Sets the specified event object to the nonsignaled state.
SetEvent Sets the specified event object to the signaled state.

OK上面是Event的基本函数(也可以直接点击进去CSDN看参数什么的下面是我的部分翻译),那么下面我面就来细细的接触接触吧。

Event函数解析

HANDLECreateEvent(
LPSECURITY_ATTRIBUTESlpEventAttributes,// 安全属性
BOOLbManualReset,// 复位方式
BOOLbInitialState,// 初始状态
LPCTSTRlpName // 对象名称
);


 

参数

lpEventAttributes[输入]
一个指向SECURITY_ATTRIBUTES结构的指针,确定返回的句柄是否可被子进程继承。如果lpEventAttributes是NULL,此句柄不能被继承。
Windows NT/2000:lpEventAttributes的结构中的成员为新的事件指定了一个安全符。如果lpEventAttributes是NULL,事件将获得一个默认的安全符。
bManualReset[输入]
指定将事件对象创建成手动复原还是自动复原。如果是TRUE,那么必须用ResetEvent函数来手工将事件的状态复原到无信号状态。如果设置为FALSE,当事件被一个等待线程释放以后,系统将会自动将事件状态复原为无信号状态。
bInitialState[输入]
指定事件对象的初始状态。如果为TRUE,初始状态为有信号状态;否则为无信号状态。
lpName[输入]
指定事件的对象的名称,是一个以0结束的字符串指针。名称的字符格式限定在MAX_PATH之内。名字是对大小写敏感的。
如果lpName指定的名字,与一个存在的命名的事件对象的名称相同,函数将请求EVENT_ALL_ACCESS来访问存在的对象。这时候,由于bManualReset和bInitialState参数已经在创建事件的进程中设置,这两个参数将被忽略。如果lpEventAttributes是参数不是NULL,它将确定此句柄是否可以被继承,但是其安全描述符成员将被忽略。
如果lpName为NULL,将创建一个无名的事件对象。
如果lpName的和一个存在的信号、互斥、等待计时器、作业或者是文件映射对象名称相同,函数将会失败,在GetLastError函数中将返回ERROR_INVALID_HANDLE。造成这种现象的原因是这些对象共享同一个命名空间。

一个Event被创建以后,可以用OpenEvent()API来获得它的Handle,用CloseHandle()  来关闭它,用SetEvent()或PulseEvent()来设置它使其有信号,用ResetEvent()  来使其无信号,用WaitForSingleObject()或WaitForMultipleObjects()来等待   其变为有信号.   

PulseEvent()是一个比较有意思的使用方法,正如这个API的名字,它使一个Event    对象的状态发生一次脉冲变化,从无信号变成有信号再变成无信号,而整个操作是原子的.    对自动复位的Event对象,它仅释放第一个等到该事件的thread(如果有),而对于    人工复位的Event对象,它释放所有等待的thread

 

OpenEvent

HANDLEOpenEvent(
DWORD dwDesiredAccess,
BOOL bInheritHandle,
LPCTSTR lpName
);


 参数说明

dwDesiredAccess 【in】指定对事件对象的请求访问权限,如果安全描述符指定的对象不允许要求通过对调用该函数的过程,函数将返回失败。
该参数必须设置为以下值:
EVENT_ALL_ACCESS 指定事件对象所有可能的权限
bInheritHandle 【in】指定是否返回的句柄是否继承 。该参数必须设置为false
lpName 【in】指向一个以null结束的字符串,即将要打开的事件对象的名字。名称是区分大小写的。
 
 

Event 原理就先说那么多吧,上面没有提及的函数,在我前面的文章都有详细的说明和解析!

 

最后总结下事件Event(morewindows)

1.事件是内核对象,事件分为手动置位事件自动置位事件。事件Event内部它包含一个使用计数(所有内核对象都有),一个布尔值表示是手动置位事件还是自动置位事件,另一个布尔值用来表示事件有无触发。

2.事件可以由SetEvent()来触发,由ResetEvent()来设成未触发。还可以由PulseEvent()来发出一个事件脉冲。

3.事件可以解决线程间同步问题,因此也能解决互斥问题

 

下一篇《C++ 经典线程同步 事件Event案例解析第九篇》将介绍使用事件Event来解决这个经典线程同步问题。

 

期待将持续更新! syw_selfimpr新浪微博地址: http://weibo.com/u/2945271402 

注:以上在VS2010 下运行编译!

 

展开阅读全文

没有更多推荐了,返回首页