【事件】
事件用处多是控制线程间的同步。
最典型的应用就是CreateThread之后等待线程函数的启动。如Main线程里CreateThread,它之后的操作依赖于子线程,那么它一般会在CreateThread之后判断HANDLE是否有效,然后进入等待。(当然在这之前,一个Event是已经创建好的,并初始化为未通知状态)子线程启动后完成了初始化操作,并设置Event为已通知状态。这时,一直在等待该事件的Main线程发现该事件已经得到通知,因此它就变成可调度线程。这时Main线程知道子线程已经完成了初始化操作。
CreateEvent函数用于创建一个Event,其原型如下:
参数说明:
应用程序能够确定它是否确实创建了一个新内核对象,而不是打开了一个现有的对象。方法是在调用C r e a t e *函数后立即调用G e t L a s t E r r o r:如果为ERROR_ALREADY_EXISTS,那么表示系统内已经存在了这样名字的对象。
Open*是去查看名字空间中是否有这个名字的内核对象存在调用C r e a t e *函数与调用O p e n *函数之间的主要差别是,如果对象并不存在,那么C r e a t e *函数将创建该对象,而O p e n *函数则运行失败。
PulseEvent函数使得事件变为已通知状态,然后立即又变为未通知状态,这就像在调用SetEvent后又立即调用ResetEvent函数一样。如果在人工重置的事件上调用PulseEvent函数,那么在发出该事件时,等待该事件的任何一个线程或所有线程将变为可调度线程。如果在自动重置事件上调用P u l s e E v e n t函数,那么只有一个等待该事件的线程变为可调度线程。如果在发出事件时没有任何线程在等待该事件,那么将不起任何作用。
【等待函数】
等待函数用来监听事件的已通知状态。WaitForSingleObject和WaitForMultipleObjects两个函数分别用以等待单个事件和多个事件。
从函数原型上来看可知,事件的含义是能够支持被通知/未通知的内核对象(例如进程和线程,当传入的是进程或者线程句柄时,他表示等该线程或进程被标识为终止运行为止。)。
dwMilliseconds参数表明等待的时间,如果在这个时间段中事件为已通知状态,那么对于Single版本将返回WAIT_OBJECT_0,对于Multiple版本将返回WAIT_OBJECT_0 to (WAIT_OBJECT_0 + nCount– 1)。如果没有等到将返回WAIT_TIMEOUT。
Multiple版本中的bWaitAll表示想要让它使用何种方式等待。如果为该参数传递TRUE,那么在所有对象变为已通知状态之前,该函数将不允许调用线程运行。一般是FALSE,即只要有一个事件被相应,则线程可调度。
事件用处多是控制线程间的同步。
最典型的应用就是CreateThread之后等待线程函数的启动。如Main线程里CreateThread,它之后的操作依赖于子线程,那么它一般会在CreateThread之后判断HANDLE是否有效,然后进入等待。(当然在这之前,一个Event是已经创建好的,并初始化为未通知状态)子线程启动后完成了初始化操作,并设置Event为已通知状态。这时,一直在等待该事件的Main线程发现该事件已经得到通知,因此它就变成可调度线程。这时Main线程知道子线程已经完成了初始化操作。
CreateEvent函数用于创建一个Event,其原型如下:
HANDLE CreateEvent(
LPSECURITY_ATTRIBUTES lpEventAttributes,
BOOL bManualReset,
BOOL bInitialState,
LPTSTR lpName
);
LPSECURITY_ATTRIBUTES lpEventAttributes,
BOOL bManualReset,
BOOL bInitialState,
LPTSTR lpName
);
- 第一个参数同CreateThread类似,也是安全级别相关,通常被被设置为NULL,以获得默认的安全级别。
- 第二个参数是个布尔值,它能够告诉系统是创建一个人工重置的事件(TRUE)还是创建一个自动重置的事件( FALSE)。
- 第三个参数也是布尔值,用于指明该事件是要初始化为已通知状态(TRUE)还是未通知状态(FALSE)。
- 第四个参数是一个字符串,用于标示这个事件的名字。
- 已通知状态和未通知状态
事件只有两种状态,已通知表示这个事件已经被设置过了(可以理解为发生了),未通知表示还没有发生。一般设置为未通知状态,并由SetEvent设置为已通知状态。当然也可以反着做,CreateEvent时设置为已通知状态,然后由ResetEvent设置为未通知状态。 - 人工重置与自动重置
自动重置的事件定义了应该成功等待的副作用规则,即当线程成功地等待到该对象时,自动重置的事件就会自动重置到未通知状态。
人工重置则需要调用ResetEvent函数设置为未通知状态。 - 名字共享
这个参数很重要,Win32 API中有很多方法有这个参数,它遵从一种按名字共享的规则。
如果传入一个非NULL字符串(最多260个字符),那么在全局空间,共享该HANDLE,这个全局可以是跨进程的名字空间,即在另一个进程中依然能够使用该名字的HANDLE。
如果希望避免这种全局范围内的共享,那么应该传入NULL,以一种匿名的方式创建Event等,这样,它只在当前线程内可见。
应用程序能够确定它是否确实创建了一个新内核对象,而不是打开了一个现有的对象。方法是在调用C r e a t e *函数后立即调用G e t L a s t E r r o r:如果为ERROR_ALREADY_EXISTS,那么表示系统内已经存在了这样名字的对象。
Open*是去查看名字空间中是否有这个名字的内核对象存在调用C r e a t e *函数与调用O p e n *函数之间的主要差别是,如果对象并不存在,那么C r e a t e *函数将创建该对象,而O p e n *函数则运行失败。
PulseEvent函数使得事件变为已通知状态,然后立即又变为未通知状态,这就像在调用SetEvent后又立即调用ResetEvent函数一样。如果在人工重置的事件上调用PulseEvent函数,那么在发出该事件时,等待该事件的任何一个线程或所有线程将变为可调度线程。如果在自动重置事件上调用P u l s e E v e n t函数,那么只有一个等待该事件的线程变为可调度线程。如果在发出事件时没有任何线程在等待该事件,那么将不起任何作用。
【等待函数】
等待函数用来监听事件的已通知状态。WaitForSingleObject和WaitForMultipleObjects两个函数分别用以等待单个事件和多个事件。
DWORD WaitForSingleObject(
HANDLE hHandle,
DWORD dwMilliseconds
);
DWORD WaitForMultipleObjects(
DWORD nCount,
const HANDLE * lpHandles,
BOOL bWaitAll,
DWORD dwMilliseconds
);
HANDLE hHandle,
DWORD dwMilliseconds
);
DWORD WaitForMultipleObjects(
DWORD nCount,
const HANDLE * lpHandles,
BOOL bWaitAll,
DWORD dwMilliseconds
);
dwMilliseconds参数表明等待的时间,如果在这个时间段中事件为已通知状态,那么对于Single版本将返回WAIT_OBJECT_0,对于Multiple版本将返回WAIT_OBJECT_0 to (WAIT_OBJECT_0 + nCount– 1)。如果没有等到将返回WAIT_TIMEOUT。
Multiple版本中的bWaitAll表示想要让它使用何种方式等待。如果为该参数传递TRUE,那么在所有对象变为已通知状态之前,该函数将不允许调用线程运行。一般是FALSE,即只要有一个事件被相应,则线程可调度。