事件EVENT,WaitForSingleObject(),WaitForMultipleObjecct()和SignalObjectAndWait() 的使用(下)

注意:当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或更高版本。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/448255.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

设置 shell 脚本中 echo 显示内容带颜色

前些天发现了一个巨牛的人工智能学习网站&#xff0c;通俗易懂&#xff0c;风趣幽默&#xff0c;忍不住分享一下给大家。点击跳转到教程。 shell脚本中echo显示内容带颜色显示,echo显示带颜色&#xff0c;需要使用参数 -e 格式如下&#xff1a; echo -e "\033[字背景颜…

Visual C++ 编译器选项 /MD、/ML、/MT、/LD

前段时间编译一个引用自己写的静态库的程序时老是出现链接时的多个重定义的错误&#xff0c;而自己的代码明明没有重定义这些东西&#xff0c;譬如&#xff1a; LIBCMT.lib(_file.obj) : error LNK2005: ___initstdio already defined in libc.lib(_file.obj) LIBCMT.lib(_fi…

Delphi面向对象编程的20条规则

Delphi面向对象编程的20条规则 作者简介 Marco Cantu是一个知名的Delphi专家&#xff0c;他曾出版过《精通Delphi》系列丛书&#xff0c;《Delphi开发手册》以及电子书《精通Pascal》(该电子书可在网上免费获得)。他讲授的课题是Delphi基础和高级开发技巧。你可以通过他…

制动失灵怎么办?

定义 制动过程中&#xff0c;由于制动器某些零部件的损坏或发生故障&#xff0c;使运动部件(或运动机械)不能保持停止状态或不能按要求停止运动的现象。 制动失灵的原因 制动失灵的关键在于制动系统无法对汽车施加足够的制动力&#xff0c;包括制动液管路液位不足或进入空气、制…

OpenDDS用idl生成自定义数据类型时遇到的一个问题

问题&#xff1a;这里会提示LNK2005重复定义的错误 解决方案&#xff1a; 解决后&#xff1a;

解决:Connect to xx.xx.xxx.xx :8081 [/xx.xx.xx.xx] failed: Connection refu sed: connect -> [H

前些天发现了一个巨牛的人工智能学习网站&#xff0c;通俗易懂&#xff0c;风趣幽默&#xff0c;忍不住分享一下给大家。点击跳转到教程。 1. 自行启动了个 Nenux 服务。想把本地工程推送到 个人私服&#xff0c;执行命令&#xff1a;mvn deploy 报错&#xff1a; Failed to…

ADOQuery 查询 删除 修改 插入

//利用combobox组件查询数据库表procedure TForm1.Button1Click(Sender: TObject);beginADOQuery1.Close;ADOQuery1.SQL.Clear;ADOQuery1.SQL.Add(select * from trim(ComboBox2.Text));ADOQuery1.Active:true;end&#xff1b; //查询记录procedure TForm1.Button1Click(Sender…

防爆胎,有妙招

对于大多数人来说&#xff0c;买车难,养车更难。许多人拥有了新车&#xff0c;却没有足够的知识去好好保养汽车&#xff0c;这实在是非常可惜。如何做好汽车的保养工作,让我们的爱车更好的为我们工作&#xff1f;夏天炽热的天气&#xff0c;是否让你为爆胎烦恼不已&#xff1f;…

Qt之QProcess(一)运行cmd命令

Qt提供了QProcess类&#xff0c;QProcess可用于完毕启动外部程序&#xff0c;并与之交互通信。 一、启动外部程序的两种方式&#xff1a; &#xff08;1&#xff09;一体式&#xff1a;void QProcess::start(const QString & program, const QStringList & arguments…

Docker 方式安装 Nexus 私服

前些天发现了一个巨牛的人工智能学习网站&#xff0c;通俗易懂&#xff0c;风趣幽默&#xff0c;忍不住分享一下给大家。点击跳转到教程。 1. 从Docker 官方仓库查找镜像&#xff1a; docker search nexus 2. 拉取镜像&#xff1a; docker pull 你选中的镜像的名字  pull…

shader飞线改进版

项目github地址&#xff1a;https://github.com/ecojust/flyline 前面写过一个飞线(基于THREE.Line进行的颜色变化)&#xff0c;只是简单地将可视区片元颜色的alpha通道值设为1.0&#xff0c;不在可视区的设为0.0。效果是这样的&#xff1a; 做得很粗糙&#xff0c;而且因为线是…

转向盘失控怎么办?

定义 转向失控就是方向盘不管用了&#xff0c;打方向盘&#xff0c;但是前轮不动&#xff0c;不受方向盘控制。 转向失控的原因 转向失控可能因为车辆过快、酒驾、疲劳、车况不佳、雨雪路滑等&#xff0c;还有转向机构中有零部件脱落、损坏、卡滞时&#xff0c;也会使转向机构突…

Socket网络编程【获取本机IP】

//12.3.2//运行环境VS2013//获取本地IP #include <stdio.h> #include <winsock2.h> #pragma comment(lib,"ws2_32.lib")void main() { // 调用WSAStarup初始化WINsock库 WSADATA wsaData; ::WSAStartup( MAKEWORD(2,2), &wsaData);// 存放主机名的…

onresize

1 window.onresize function (ev) { 2 console.log(尺寸发生改变&#xff01;); 3 }; 4 5 window.addEventListener(resize, function (ev) { 6 console.log(尺寸发生改变&#xff01;); 7 }); 1 /*2 当屏幕的宽度>960时&#xff0c;页面的背景颜色为红色…

Vuejs:组件 slot 内容分发

前些天发现了一个巨牛的人工智能学习网站&#xff0c;通俗易懂&#xff0c;风趣幽默&#xff0c;忍不住分享一下给大家。点击跳转到教程。 本文是在官方文档的基础上&#xff0c;更加细致的说明&#xff0c;代码更多更全。 简单来说&#xff0c;更适合新手阅读 &#xff08;…

C++获取本机所有ip地址,可区分类型是有线无线虚拟机还是回环

一个小程序&#xff0c;可以获取本地所有ip地址&#xff0c;包括有线&#xff0c;无线&#xff0c;虚拟机&#xff0c;环回接口网卡&#xff0c;等。 如图&#xff0c;一台机器多个网卡&#xff1a; 程序执行结果&#xff1a; #include"stdio.h" #include"…

顿悟人生十一句话

一、永远不要埋怨你已经发生的事情 如果你打算忍受一件事情就闭上嘴巴吧。要么就改变它&#xff0c;要么就安静的接受它。 二、最让你忿忿不平的问题&#xff0c;就是你需要解决的问题 一个被酒后驾驶的司机撞死自己儿子的妇女&#xff0c;发起了反对酒后驾驶母亲协会…

Mybatis 在 IDEA 中使用 generator 逆向工程生成 pojo,mapper

前些天发现了一个巨牛的人工智能学习网站&#xff0c;通俗易懂&#xff0c;风趣幽默&#xff0c;忍不住分享一下给大家。点击跳转到教程。 使用mybatis可以逆向生成pojo和mapper文件有很多种方式&#xff0c;我以前用的是mybtais自带的generator包来生成&#xff0c;连接如下&…

控制台程序隐藏方法总结(四种)

学习计算机&#xff0c;往往先从Windows环境下学习编程&#xff0c;学习编程&#xff0c;往往从C学起&#xff0c;学习C&#xff0c;往往又从控制台程序学习&#xff0c;何为控制台&#xff0c;就是那个黑框白字的界面。对于这样一个最初认为奇陋无比而现在认为无所不能的编程平…

十大教养,让你气度非凡!

01.守时 无论是开会、赴约&#xff0c;有教养的人从不迟到。他们懂得&#xff0c;即使是无意迟到&#xff0c;对其他准时到场的人来说&#xff0c;也是不尊重的表现。 02.谈吐有节 注意从不随便打断别人的谈话&#xff0c;总是先听完对方的发言&#xff0c;然后再去反驳或者补…