Win32 API 常用函数之二

【事件】
       事件用处多是控制线程间的同步。
       最典型的应用就是CreateThread之后等待线程函数的启动。如Main线程里CreateThread,它之后的操作依赖于子线程,那么它一般会在CreateThread之后判断HANDLE是否有效,然后进入等待。(当然在这之前,一个Event是已经创建好的,并初始化为未通知状态)子线程启动后完成了初始化操作,并设置Event为已通知状态。这时,一直在等待该事件的Main线程发现该事件已经得到通知,因此它就变成可调度线程。这时Main线程知道子线程已经完成了初始化操作。
       CreateEvent函数用于创建一个Event,其原型如下:
HANDLE CreateEvent(
  LPSECURITY_ATTRIBUTES lpEventAttributes, 
  BOOL bManualReset, 
  BOOL bInitialState, 
  LPTSTR lpName 
); 
       参数说明:
  1. 第一个参数同CreateThread类似,也是安全级别相关,通常被被设置为NULL,以获得默认的安全级别。
  2. 第二个参数是个布尔值,它能够告诉系统是创建一个人工重置的事件(TRUE)还是创建一个自动重置的事件( FALSE)。
  3. 第三个参数也是布尔值,用于指明该事件是要初始化为已通知状态(TRUE)还是未通知状态(FALSE)。
  4. 第四个参数是一个字符串,用于标示这个事件的名字。
       以下是详细说明:
  1. 已通知状态和未通知状态
    事件只有两种状态,已通知表示这个事件已经被设置过了(可以理解为发生了),未通知表示还没有发生。一般设置为未通知状态,并由SetEvent设置为已通知状态。当然也可以反着做,CreateEvent时设置为已通知状态,然后由ResetEvent设置为未通知状态。
  2. 人工重置与自动重置
    自动重置的事件定义了应该成功等待的副作用规则,即当线程成功地等待到该对象时,自动重置的事件就会自动重置到未通知状态。
    人工重置则需要调用ResetEvent函数设置为未通知状态。
  3. 名字共享
    这个参数很重要,Win32 API中有很多方法有这个参数,它遵从一种按名字共享的规则。
    如果传入一个非NULL字符串(最多260个字符),那么在全局空间,共享该HANDLE,这个全局可以是跨进程的名字空间,即在另一个进程中依然能够使用该名字的HANDLE。
    如果希望避免这种全局范围内的共享,那么应该传入NULL,以一种匿名的方式创建Event等,这样,它只在当前线程内可见。
        当进程A创建了一个Event后,如CreateEvent(NULL,FALSE,FLASE,_T(“UniqueEvent”));进程B同样创建了一个Event,也想起名字为UniqueEvent,那么就会出现问题:CreateEvent(NULL,FALSE,FALSE,_T(“UniqueEvent”));系统会首先查看是否已经存在了一个名字为“UniqueEvent”的对象,由于确实存在了一个带有改名字的内核对象,因此内核要检查对象类型,同样是一 个Event,那么系统会执行一次安全检查,以确定调用者是否拥有对该对象的完整访问权。如果有这种访问权,系统会在进程B的句柄表里找到一个空项目,对 其初始化,使得该项指向现有的内核对象。如果类型不匹配,或者拒绝访问,那么进程B的CreateEvent会失败。
       应用程序能够确定它是否确实创建了一个新内核对象,而不是打开了一个现有的对象。方法是在调用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
);
       从函数原型上来看可知,事件的含义是能够支持被通知/未通知的内核对象(例如进程和线程,当传入的是进程或者线程句柄时,他表示等该线程或进程被标识为终止运行为止。)。
       dwMilliseconds参数表明等待的时间,如果在这个时间段中事件为已通知状态,那么对于Single版本将返回WAIT_OBJECT_0,对于Multiple版本将返回WAIT_OBJECT_0 to (WAIT_OBJECT_0 + nCount– 1)。如果没有等到将返回WAIT_TIMEOUT。
       Multiple版本中的bWaitAll表示想要让它使用何种方式等待。如果为该参数传递TRUE,那么在所有对象变为已通知状态之前,该函数将不允许调用线程运行。一般是FALSE,即只要有一个事件被相应,则线程可调度。

      
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值