注意:当WaitForMultipleObjects等待多个内核对象的时候,如果它的bWaitAll 参数设置为false。其返回值减去WAIT_OBJECT_0 就是参数lpHandles数组的序号。如果同时有多个内核对象被触发,这个函数返回的只是其中序号最小的那个。

如果bWaitAll 为TRUE 则等待所有信号量有效在往下执行。(FALSE 当有其中一个信号量有效时就向下执行)

问题就在这里,我们如何可以获取所有被同时触发的内核对象。

举个例子:我们需要在一个线程中处理从完成端口、数据库、和可等待定时器来的数据。一个典型的实现方法就是:用WaitForMultipleObjects等待所有的这些事件。如果完成端口,数据库发过来的数据量非常大,可等待定时器时间也只有几十毫秒。那么这些事件同时触发的几率可以说非常大,我们不希望丢弃任何一个被触发的事件。那么如何能高效地实现这一处理呢?   

MSDN中有一句非常重要的描述,它可以说是WaitForMultipleObjects用法的精髓:The function modifies the state of some types of synchronization objects. Modification occurs only for the object or objects whose signaled state caused the function to return. For example, the count of a semaphore object is decreased by one. When bWaitAll is FALSE, and multiple objects are in the signaled state, the function chooses one of the objects to satisfy the wait; the states of the objects not selected are unaffected.   

多个内核对象被触发时,WaitForMultipleObjects选择其中序号最小的返回。而WaitForMultipleObjects它只会改变使它返回的那个内核对象的状态。

这儿又会产生一个问题,如果序号最小的那个对象频繁被触发,那么序号比它大的内核对象将得不到被处理的机会。为了解决这一问题,可以采用双WaitForMultipleObjects检测机制来实现。见下面的例子:

DWORD WINAPI ThreadProc(LPVOID lpParameter)   
{   DWORD dwRet = 0;   int nIndex = 0;   while(1)   { dwRet = WaitForMultipleObjects(nCount,pHandles,false,INFINITE);   switch(dwRet)   {case WAIT_TIMEOUT:   break;   case WAIT_FAILED:   return 1;default:{nIndex = dwRet - WAIT_OBJECT_0;   ProcessHanlde(nIndex++);   //同时检测其他的事件   while(nIndex < nCount) //nCount事件对象总数   {   dwRet = WaitForMultipleObjects(nCount - nIndex,&pHandles[nIndex],false,0);   switch(dwRet)   {case WAIT_TIMEOUT:   nIndex = nCount; //退出检测,因为没有被触发的对象了.   break;case WAIT_FAILED:   return 1;   default:{nIndex = dwRet - WAIT_OBJECT_0;   ProcessHanlde(nIndex++);   }break;}//switch结束}//while结束}//default结束break;}//switch结束}//while结束return 0;
}

SignalObjectAndWait()

你也可以同时通知一个内核对象,同时等待另一个内核对象,这两个操作以原子的方式进行。
语法

DWORD SignalObjectAndWait(HANDLE hObjectToSignal,//通知的内核对象HANDLE hObjectToWaitOn,//等待的内核对象DWORD  dwMilliseconds,//等待的时间BOOL   bAlertable//与IO完成端口有关的参数,暂不讨论
);

参数

  • hObjectToSignal
    要发信号的对象的句柄。此对象可以是信号量,互斥量或事件。
    如果句柄是信号量,则需要SEMAPHORE_MODIFY_STATE访问权限。如果句柄是事件,则需要EVENT_MODIFY_STATE访问权限。如果句柄是互斥锁且调用者不拥有互斥锁,则函数将失败并显示ERROR_NOT_OWNER。

  • hObjectToWaitOn
    要等待的对象的句柄。该SYNCHRONIZE访问权是必需的; 有关更多信息,请参阅同步对象安全性和访问权限 。有关可以指定其句柄的对象类型的列表,请参阅“备注”部分。

  • dwMilliseconds
    超时间隔,以毫秒为单位。即使对象的状态是非信号且没有完成或异步过程调用(APC)对象排队,该函数也会在间隔过去时返回。如果dwMilliseconds为零,则该函数测试对象的状态,检查排队的完成例程或APC,并立即返回。如果dwMilliseconds是INFINITE,则函数的超时间隔永远不会过去。

  • bAlertable
    如果此参数为TRUE,则该函数在系统对I / O完成例程或APC函数进行排队时返回,并且该线程调用该函数。如果为FALSE,则函数不返回,并且线程不调用完成例程或APC函数。
    当排队APC的函数调用完成时,完成例程排队。只有当bAlertable为TRUE且调用线程是排队APC的线程时,此函数才会返回并调用完成例程。

返回值

返回代码/值 描述
WAIT_ABANDONED/0x00000080L 指定的对象是在拥有线程终止之前由拥有互斥对象的线程未释放的互斥对象。互斥对象的所有权被授予调用线程,并且互斥锁被设置为无信号。如果互斥锁正在保护持久状态信息,则应检查它是否一致。
WAIT_IO_COMPLETION/0x000000C0L 等待由一个或多个排队到线程的用户模式 异步过程调用(APC)结束。
WAIT_OBJECT_0/0x00000000L 发出指定对象的状态信号。
WAIT_TIMEOUT/0x00000102L 超时间隔已过,对象的状态未发出信号。
WAIT_FAILED/(DWORD)0xFFFFFFFF 该功能失败了。要获取扩展错误信息,请调用 GetLastError。

备注
所述SignalObjectAndWait功能提供了一个更有效的方式来信号发送一个对象,然后在另一等待相比单独的函数调用诸如 SetEvent的随后WaitForSingleObject的。

该 SignalObjectAndWait函数可以等待以下对象:

  • 更改通知
  • 控制台输入
  • 事件
  • 内存资源通知
  • 互斥
  • 处理
  • 信号
  • 线

线程可以使用SignalObjectAndWait函数来确保工作线程在发信号通知对象之前处于等待状态。例如,线程和工作线程可以使用句柄来事件对象来同步它们的工作。该线程执行如下代码:

 dwRet = WaitForSingleObject(hEventWorkerDone, INFINITE);if( WAIT_OBJECT_0 == dwRet)SetEvent(hEventMoreWorkToDo);

工作线程执行如下代码:

dwRet = SignalObjectAndWait(hEventWorkerDone,hEventMoreWorkToDo,INFINITE, FALSE);

注意,“信号”和“等待”不能保证作为原子操作执行。在调用SignalObjectAndWait的线程开始等待第二个对象之前,在其他处理器上执行的线程可以观察第一个对象的信号状态。

在Windows 7中使用SignalObjectAndWait 和PulseEvent时要格外小心 ,因为在多个线程之间使用这些API会导致应用程序死锁。由信号发送线程SignalObjectAndWait 调用PulseEvent以发信号通知的等待对象SignalObjectAndWait呼叫。在某些情况下,SignalObjectAndWait的调用者无法及时接收等待对象的信号状态,从而导致死锁。

使用等待函数和直接或间接创建窗口的代码时要小心。如果一个线程创建了任何窗口,它必须处理消息。消息广播将发送到系统中的所有窗口。使用没有超时间隔的等待函数的线程可能会导致系统死锁。间接创建窗口的两个代码示例是DDE和COM CoInitialize。因此,如果您有一个创建窗口的线程,请务必从另一个线程调用SignalObjectAndWait。如果无法做到这一点,可以使用 MsgWaitForMultipleObjects或 MsgWaitForMultipleObjectsEx,但功能不相同。

要编译使用此函数的应用程序,请将 _WIN32_WINNT 定义为0x0400或更高版本。

事件EVENT,WaitForSingleObject(),WaitForMultipleObjecct()和SignalObjectAndWait() 的使用(下)相关推荐

  1. 事件EVENT,WaitForSingleObject(),WaitForMultipleObjecct()和SignalObjectAndWait() 的使用(上)

    用户模式的线程同步机制效率高,如果需要考虑线程同步问题,应该首先考虑用户模式的线程同步方法.但是,用户模式的线程同步有限制,对于多个进程之间的线程同步,用户模式的线程同步方法无能为力.这时,只能考虑使 ...

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

    Mutex与Event控制互斥事件的使用详解最近写一程序,误用了Mutex的功能,错把Mutex当Event用了.[Mutex]使用Mutex的主要函数:CreateMutex.ReleaseMute ...

  3. 秒杀多线程第六篇 经典线程同步 事件Event

    阅读本篇之前推荐阅读以下姊妹篇: <秒杀多线程第四篇 一个经典的多线程同步问题> <秒杀多线程第五篇 经典线程同步关键段CS> 上一篇中使用关键段来解决经典的多线程同步互斥问题 ...

  4. 经典线程同步 事件Event

    Event 内核对象,实际上是解决线程同步问题的利器. 介绍下函数应用: 第一个 CreateEvent 函数功能:创建事件 函数原型: HANDLECreateEvent( LPSECURITY_A ...

  5. 互斥量(mutex)与事件(event)的使用

    互斥量(Mutex) CreateMutex :创建一个互斥量 HANDLE   CreateMutex(             LPSECURITY_ATTRIBUTES   lpMutexAtt ...

  6. Windows多线程(四) 经典线程同步 事件Event

    第一个 CreateEvent 函数功能:创建事件 函数原型: HANDLECreateEvent( LPSECURITY_ATTRIBUTESlpEventAttributes, BOOLbManu ...

  7. C#事件(event)解析

    原文:http://www.cnblogs.com/michaelxu/archive/2008/04/02/1134217.html 事件(event),这个词儿对于初学者来说,往往总是显得有些神秘 ...

  8. js事件(Event)知识整理

    鼠标事件 鼠标移动到目标元素上的那一刻,首先触发mouseover  之后如果光标继续在元素上移动,则不断触发mousemove  如果按下鼠标上的设备(左键,右键,滚轮--),则触发mousedow ...

  9. python 同步 事件 event 简介

    目录 1. Event 1.1 set() 1.2 wait() 1.3 clear() 1.4 is_set() 2. 协调线程同步 3. 一个更复杂的例子 事件 Event是另一种python多线 ...

  10. [数据库] Navicat for MySQL事件Event实现数据每日定期操作

    在我们操作数据库过程中,通常会遇到一些某个时间点操作数据库的问题,例如:         (1).每天凌晨12点对数据库进行定时备份,结算和汇总:         (2).每天凌晨2点删除数据库前三天 ...

最新文章

  1. qmake 简易教程
  2. fork() 成为负担,需要淘汰
  3. 北京师范大学计算机应用基础考试,北京师范大学-计算机应用基础作业(一至九全套)...
  4. redhat下安装mysql 5.6.20,解压zip包,查看已经安装过的mysql,卸载rpm安装包,安装mysql服务器端和客户端,修改mysql用户名,登陆mysql,启动关闭mysql
  5. 远程管理服务器的具体操作方法
  6. Maven项目有红叉,文件却没有错误,已解决
  7. go还是python 知乎_知乎用Go替代Python
  8. 兜兜转转,回到原点,Hello Mr.my yesterday
  9. 全局变量反汇编与重定位
  10. 2022.03.15 Arcmap栅格数据无法按照拟定范围进行重分类的解决方案
  11. apscheduler报错maximum number of running instances
  12. CSDN博客之星——找到自己的榜样
  13. gcd函数(C/C++)
  14. Android reckon 控制项目打包版本
  15. 这样的跳槽理由HR不排斥,赶紧记好!
  16. Linux systemd启动流程
  17. uniapp 自制头部左侧胶囊组件
  18. Android HAL层到驱动代码搜索---基于背光亮度的调试
  19. Stata绘图相关问题
  20. XSS Challenges xss-quiz.int21h.jp

热门文章

  1. android studio 库工程,Android Studio 添加已有工程方法
  2. php字符串变量,PHP 字符串变量
  3. 计算机应用基础形考作业3Excel,国家开放大学《计算机应用基础》考试与答案形考任务模块3 模块3 Excel 电子表格系统—客观题答案(2020年整理).pptx...
  4. cancase vector_基于Vector总线设备的CAN总线测试方法概述
  5. oracle更换rac节点,Oracle-rac 更改VIP地址—2节点的
  6. java 批量打印_JAVA批量打印皕杰报表
  7. shell预先定义的特殊变量
  8. leetcode74. 搜索二维矩阵 ,你见过吗
  9. 关系数据库——sql基础1定义
  10. python基础小白题5