WaitForSingleObject和WaitForMultipleObjects用法
转自:http://www.360doc.com/content/10/0512/09/1072296_27178529.shtml
等待函数可使线程自愿进入等待状态,直到一个特定的内核对象变为已通知状态为止。这些等待函数中最常用的是WaitForSingleObject:
DWORD WaitForSingleObject(HANDLE hObject, DWORD dwMilliseconds);
当线程调用该函数时,第一个参数hObject标识一个能够支持被通知/未通知的内核对象。第二个参数dwMilliseconds.允许该线程指明,为了等待该对象变为已通知状态,它将等待多长时间。调用下面这个函数将告诉系统,调用函数准备等待到hProcess句柄标识的进程终止运行为止:
WaitForSingleObject(hProcess, INFINITE);
第二个参数告诉系统,调用线程愿意永远等待下去(无限时间量),直到该进程终止运行。
通常情况下, INFINITE是作为第二个参数传递给WaitForSingleObject的,不过也可以传递任何一个值(以毫秒计算)。顺便说一下, INFINITE已经定义为0xFFFFFFFF(或-1)。当然,传递INFINITE有些危险。如果对象永远不变为已通知状态,那么调用线程永远不会被唤醒,它将永远处于死锁状态,
不过,它不会浪费宝贵的CPU时间。
下面是如何用一个超时值而不是INFINITE来调用WaitForSingleObject的例子:
DWORD dw = WaitForSingleObject(hProcess, 5000);
switch(dw)
{
case WAIT_OBJECT_0:
// The process terminated.
break;
case WAIT_TIMEOUT:
// The process did not terminate within 5000 milliseconds.
break;
case WAIT_FAILED:
// Bad call to function (invalid handle?)
break;
}
上面这个代码告诉系统,在特定的进程终止运行之前,或者在5 0 0 0 m s时间结束之前,调用线程不应该变为可调度状态。因此,如果进程终止运行,那么这个
函数调用将在不到5000ms的时间内返回,如果进程尚未终止运行,那么它在大约5000ms时间内返回。注意,不能为dwMilliseconds传递0。如果传递了0,WaitForSingleObject函数将总是立即返回。WaitForSingleObject的返回值能够指明调用线程为什么再次变为可调度状态。如果线程等待的对象变为已通知状态,那么返回值是WAIT_OBJECT_0。如果设置的超时已经到期,则返回值是WAIT_TIMEOUT。如果将一个错误的值(如一个无效句柄)传递给WaitForSingleObject,那么返回值将是WAIT_FAILED(若要了解详细信息,可调用GetLastError)。
下面这个函数WaitForMultipleObjects与WaitForSingleObject函数很相似,区别在于它允许调用线程同时查看若干个内核对象的已通知状态:
DWORD WaitForMultipleObjects(DWORD dwCount,
CONST HANDLE* phObjects,
BOOL fWaitAll,
DWORD dwMilliseconds);
dwCount参数用于指明想要让函数查看的内核对象的数量。这个值必须在1与MAXIMUM_WAIT_OBJECTS(在Windows头文件中定义为64)之间。phObjects参数是指向内核对象句柄的数组的指针。
可以以两种不同的方式来使用WaitForMultipleObjects函数。
一种方式是让线程进入等待状态,直到指定内核对象中的任何一个变为已通知状态。
另一种方式是让线程进入等待状态,直到所有指定的内核对象都变为已通知状态。fWaitAll参数告诉该函数,你想要让它使用何种方式。如果为该参数传递TRUE,那么在所有对象变为已通知状态之前,该函数将不允许调用线程运行。
dwMilliseconds参数的作用与它在WaitForSingleObject中的作用完全相同。如果在等待的时候规定的时间到了,那么该函数无论如何都会返回。同样,通常为该参数传递INFINITE,但是在编写代码时应该小心,以避免出现死锁情况。
WaitForMultipleObjects函数的返回值告诉调用线程,为什么它会被重新调度。可能的返回值是WAIT_FAILED和WAIT_TIMEOUT,这两个值的作用是很清楚的。如果fWaitAll参数传递TRUE,同时所有对象均变为已通知状态,那么返回值是WAIT_OBJECT_0。如果为fWaitAll传递FALSE,那么一旦任何一个对象变为已通知状态,该函数便返回。在这种情况下,你可能想要知道哪个对象变为已通知状态。返回值是WAIT_OBJECT_0 与(WAIT_OBJECT_0 + dwCount-1)之间的一个值。换句话说,如果返回值不是WAIT_TIMEOUT,也不是WAIT_FAILED,那么应该从返回值中减去WAIT_OBJECT_0。产生的数字是作为第二个参数传递给WaitForMultipleObjects的句柄数组中的索引。该索引说明哪个对象变为已通知状态。
下面是说明这一情况的一些示例代码:
HANDLE h[3];
h[0] = hProcess1;
h[1] = hProcess2;
h[2] = hProcess3;
DWORD dw = WaitForMultipleObjects(3, h, FALSE, 5000);
switch(dw)
{
case WAIT_FAILED:
// Bad call to function (invalid handle?)
break;
case WAIT_TIMEOUT:
// None of the objects became signaled within 5000 milliseconds.
break;
case WAIT_OBJECT_0 + 0:
// The process identified by h[0] (hProcess1) terminated.
break;
case WAIT_OBJECT_0 + 1:
// The process identified by h[1] (hProcess2) terminated.
break;
case WAIT_OBJECT_0 + 2:
// The process identified by h[2] (hProcess3) terminated.
break;
}
如果为fWaitAll参数传递FALSE,WaitForMultipleObjects就从索引0开始向上对句柄数组进行扫描,同时已通知的第一个对象终止等待状态。这可能产生一些你不希望有的结果。例如,通过将3个进程句柄传递给该函数,你的线程就会等待3个子进程终止运行。如果数组中索引为0的进程终止运行,WaitForMultipleObjects就会返回。这时该线程就可以做它需要的任何事情,然后循环反复,等待另一个进程终止运行。如果该线程传递相同的3个句柄,该函数立即再次返回WAIT_OBJECT_0。除非删除已经收到通知的句柄,否则代码就无法正确地运行。
http://www.cnblogs.com/EmbeddedBoy/archive/2010/03/09/1681095.html
WaitForSingleObject 当指定的对象的状态被标记或者指定的时间间隔过完时,此函数返回DWORD类型参数。
格式:
DWORD WaitForSingleObject(HANDLE hHandle,DWORD dwMilliseconds);
参数:
hHandle表示对象的句柄
dwMilliseconds指出了时间间隔;过了指定的时间,即使对象状态没发生改变,函数也会返回;如果此参数设为0,函数测试对象的状态并且立即返回;如果此参数设为INFINITE,则表示此函数的时间间隔永远不会流逝完——只有等待对象状态被标识时返回。
返回值:
成功:WAIT_OBJECT_0:表示对象的状态被标识
WAIT_TIMEOUT:表示指定时间已到而对象状态没有被标识
失败:WAIT_FAILED:表明失败
WaitForSingleObject 函数检查指定对象当前状态,如果对象的状态没有被标识,则调用的线程进入有效的等待状态。在等待对象状态被标识或者指定的时间间隔到期,线程只会占据(consume)处理器一小段时间。时间间隔需要被指定在0到0x7FFFFFFF之间的正数,最大的时间间隔值不等于无穷大而是0x7FFFFFFF,无穷大的时间间隔值是0xFFFFFFFF。任何在0x7FFFFFFF和0xFFFFFFFE之间的值都等同于0x7FFFFFFF;如果你需要一个时间间隔比0x7FFFFFFF还要大的话,使用表示不穷的值0xFFFFFFFF。
返回之前,等待函数修改了某些类型的同步对象的状态,只有当对象的信号状态引起了函数的返回时这种修改才发生。例如,一个信号量对象计数减少1。
WaitForSingleObject 函数能等待如下的各种对象:事件(Event)、线程(Thread)、进程(Process)、互斥量(Mutex)、信号量(Semaphore)。
使用时要小心调用等待函数和直接或间接产生窗口的代码。如果一个线程创建了窗口,那么它必须处理消息。广播消息发送到系统中的所有窗口。使用一个没有时间间隔的等待函数的线程可能导致系统死锁。例如,动态数据交换(DDE)协议和COM函数CoInitialize两个都间接地创建了可能导致死锁的窗口。因此,如果您有一个线程创建的窗口,使用MsgWaitForMultipleObjects 或者 MsgWaitForMultipleObjectsEx 而不是使用WaitForSingleObject。
/
http://blog.csdn.net/lyd_253261362/archive/2009/08/15/4450202.aspx
DWORD WaitForMultipleObjects(
DWORD nCount, // number of handles in the handle array
CONST HANDLE *lpHandles, // pointer to the object-handle array
BOOL fWaitAll, // wait flag
DWORD dwMilliseconds // time-out interval in milliseconds
);
其中参数
nCount 句柄的数量 最大值为MAXIMUM_WAIT_OBJECTS(64)
HANDLE 句柄数组的指针。
HANDLE 类型可以为(Event,Mutex,Process,Thread,Semaphore )数组
BOOL bWaitAll 等待的类型,如果为TRUE 则等待所有信号量有效在往下执行,FALSE 当有其中一个信号量有效时就向下执行
DWORD dwMilliseconds 超时时间 超时后向执行。 如果为WSA_INFINITE 永不超时。如果没有信号量就会在这死等。
举个例子:当 bWaitAll参数为FALSE 可以等待其中之一的事件
HANDLE m_hEvent[2];
//两事件
m_hEvent[0]=::CreateEvent(NULL, FALSE, FALSE, NULL);
m_hEvent[1]=::CreateEvent(NULL, FALSE, FALSE, NULL);
::CreateThread(NULL, 0, MyThreadProc, this, 0, NULL);
DWORD WINAPI MyThreadProc(LPVOID lpParam)
{
while(TRUE)
{ //每次等500毫秒
int nIndex = ::WaitForMultipleObjects(2, pThis->m_hEvent, FALSE,500);
if (nIndex == WAIT_OBJECT_0 + 1)
{
//第二个事件发生 //ExitThread(0); //break;
}
else if (nIndex == WAIT_OBJECT_0) //第一个事件发生
{
//第一个事件
}
else if (nIndex == WAIT_TIMEOUT) //超时500毫秒
{ //超时可作定时用
}
}
::OutputDebugString("线程结束. /n");
return 0L;}
当要处理第一个事件时,你只需执行SetEvent(m_hEvent[0]);
即可进入第一个事件的位置
当要执行第二个事件时执行SetEvent(m_hEvent[1]);
当 bWaitAll参数为TRUE 等待所有的事件
DWORD WINAPI MyThreadProc(LPVOID lpParam)
{ while(TRUE)
{ //每次等500毫秒
int nIndex = ::WaitForMultipleObjects(2, pThis->m_hEvent, TRUE,500);
if (WAIT_OBJECT_0 + 1<= nIndex <= WAIT_OBJECT_0) //所有事件发生
{
//所有的信号量都有效时(事件都发生)其中之一无效。
}
当WaitForMultipleObjects()等到多个内核对象的时候,
如果它的bWaitAll 参数设置为false。其返回值减去WAIT_OBJECT_0 就是参数lpHandles数组的序号。
如果同时有多个内核对象被出发,这个函数返回的只是其中序号最小的那个。
问题就在这里,我们如何可以获取所有被同时触发的内核对象。
举个例子:我们需要在一个线程中处理从完成端口、数据库、和可等待定时器来的数据。
一个典型的实现方法就是:用WaitForMultipleObjects等待所有的这些事件。
如果完成端口,数据库发过来的数据量非常大,可等待定时器时间也只有几十毫秒。
那么这些事件同时触发的几率可以说非常大,我们不希望丢弃任何一个被触发的事件。那么如何能高效地实现这一处理呢?
多个内核对象被触发时,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)
{
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;
}
}
}
break;
}
}
return 0;
}
http://www.51testing.com/?uid-68149-action-viewspace-itemid-73321
如果需要在一个线程中等待多个事件,则用WaitForMultipleObjects()来等待。WaitForMultipleObjects()与WaitForSingleObject()类似,
同时监视位于句柄数组中的所有句柄。这些被监视对象的句柄享有平等的优先权,任何一个句柄都不可能比其他句柄具有更高的优先权。
WaitForMultipleObjects()的函数原型为:
DWORD WaitForMultipleObjects(
DWORD nCount, // 等待句柄数
CONST HANDLE *lpHandles, // 句柄数组首地址
BOOL fWaitAll, // 等待标志
DWORD dwMilliseconds // 等待时间间隔
);
参数nCount指定了要等待的内核对象的数目,存放这些内核对象的数组由lpHandles来指向。fWaitAll对指定的这nCount个内核对象的两种等待方式
进行了指定,为TRUE时当所有对象都被通知时函数才会返回,为FALSE则只要其中任何一个得到通知就可以返回。dwMilliseconds在这里的作用与
在WaitForSingleObject()中的作用是完全一致的。如果等待超时,函数将返回WAIT_TIMEOUT。如果返回WAIT_OBJECT_0到WAIT_OBJECT_0+nCount-1中的某个
值,则说明所有指定对象的状态均为已通知状态(当fWaitAll为TRUE时)或是用以减去WAIT_OBJECT_0而得到发生通知的对象的索引(当fWaitAll为FALSE时)。
如果返回值在WAIT_ABANDONED_0与WAIT_ABANDONED_0+nCount-1之间,则表示所有指定对象的状态均为已通知,且其中至少有一个对象是被丢弃的互斥对象
(当fWaitAll为TRUE时),或是用以减去WAIT_OBJECT_0表示一个等待正常结束的互斥对象的索引(当fWaitAll为FALSE时)。
相关文章:

【面试必问】支撑百万并发的IO多路复用技术你了解吗?
多路复用其实并不是什么新技术,它的作用是在一个通讯连接的基础上可以同时进行多个请求响应处理。对于网络通讯来其实不存在这一说法,因为网络层面只负责数据传输;由于上层应用协议的制订问题,导致了很多传统服务并不能支持多路复…

DllMain already defined in dllmain.obj错误
错误 uafxcw.lib(dllmodul.obj) : error LNK2005: DllMain already defined in dllmain.obj 修改: 去掉宏定义 _USRDLL 转载于:https://blog.51cto.com/co63oc/1122378

典型的数字水印软件
转自:http://blog.csdn.net/pastora/archive/2005/04/15/348413.aspx ---- 目前,数字水印软件既有商品化产品,也有供研究用的免费软件。 商品化软件 ----提供商品化数字水印软件的公司主要有以下一些: ----1.Digimar…

AI、5G、小程序、AIoT纷纷迎来高峰,下一步开发者们要怎么办?
2018 年,上千名开发者与上百名技术专家齐聚一堂,在 CSDN 2018 AI开发者大会上以“AI技术与应用”为核心,深度聚焦人工智能的技术创新与行业应用,真正做到了“只讲技术,拒绝空谈”。今年,在产业智能化的浪潮…

linux第四课
一、配置软件仓库1.yum简介基于rpm软件包的安装部署机制自动解决软件包的依赖关系需要先配置软件仓库2.配置本地的软件仓库a.放入centos7.iso镜像文件到光驱中,确保电源开启b.命令操作# umount /dev/cdrom# ls /mnt# mount /dev/cdrom /mnt# ls /mnt# mkdir -p /rep…

图像处理和图像识别中常用的CxImage函数
1、Load:reads from disk the image in a specific format; 2、Save:saves to disk the image in a specific format; 3、Filter:2D linear filter(图像锐化,可提高图像清晰度); 4、Copy&…

大战三回合:XGBoost、LightGBM和Catboost一决高低 | 程序员硬核算法评测
作者 | LAVANYA译者 | 陆离责编 | Jane出品 | AI科技大本营(ID: rgznai100)【导读】XGBoost、LightGBM 和 Catboost 是三个基于 GBDT(Gradient Boosting Decision Tree)代表性的算法实现,今天,我们将在三轮…

云计算之Docker介绍
1. 百科简介 Docker 是一个开源的应用容器引擎,基于 Go 语言 并遵从Apache2.0协议开源。 Docker 可以让开发者打包他们的应用以及依赖包到一个轻量级、可移植的容器中,然后发布到任何流行的 Linux 机器上,也可以实现虚拟化。 容器是完全使用沙…

还在纠结垃圾分类问题?带你用Python感受ImageNet冠军模型SENet的强大
作者 | beyondma转载自CSDN博客本月1日起,上海正式开始了“史上最严“垃圾分类的规定,扔错垃圾最高可罚200元。全国其它46个城市也要陆续步入垃圾分类新时代。各种被垃圾分类逼疯的段子在社交媒体上层出不穷。其实从人工智能的角度看垃圾分类就是图像处理…

软件开发流程包含哪些内容
2019独角兽企业重金招聘Python工程师标准>>> 能否开发出一个好的软件,关键是看软件开发前期所做的工作,重点是这个软件有没有一个好的 软件开发流程,因为一个好的软件开发流程关系到到这个软件的成败和最后能达到一个什么的效果&a…

在对话框中应用CScrollView显示图像
1、用vs2008创建一个基于对话框的工程DialogView; 2、添加一个新类CMyDocument,基类为CDocument; 3、添加一个新类CMyView,基类为CScrollView; 4、修改CMyDocument的头文件: #pragma once // CMyDocument …

如何用纯 CSS 创作一个同心圆弧旋转 loader 特效
效果预览 在线演示 按下右侧的“点击预览”按钮在当前页面预览,点击链接全屏预览。 https://codepen.io/zhang-ou/pen/OZmXQX 可交互视频教程 此视频是可以交互的,你可以随时暂停视频,编辑视频中的代码。 请用 chrome, safari, edge 打开观看…

Java长见到的面试题,看你能答出几题,就知道自己有多菜了
作者:Java3y前言只有光头才能变强Redis目前还在看,今天来分享一下我在秋招看过(遇到)的一些面试题(相对比较常见的)0、final关键字简要说一下final关键字,final可以用来修饰什么?这题我是在真实的面试中遇到的,当时答得…

数据结构实验之链表一:顺序建立链表
题目描述 输入N个整数,按照输入的顺序建立单链表存储,并遍历所建立的单链表,输出这些数据。输入 第一行输入整数的个数N;第二行依次输入每个整数。输出 输出这组整数。示例输入 8 12 56 4 6 55 15 33 62 示例输出 12 56 4 6 55 15…

深度学习在人脸检测中的应用 | CSDN 博文精选
作者 | 梁志成、刘鹏、陈方杰责编 | 唐小引转载自CSDN(ID:csdnnews)在目标检测领域,可以划分为人脸检测与通用目标检测,往往人脸这方面会有专门的算法(包括人脸检测、人脸识别、人脸其他属性的识别等)&…

vs2008中,在OCX控件中应用doc/view基本步骤
1、利用向导创建一个MFC ActiveX Control控件CMyOCX; 2、在工程中加入ActivDoc头文件和执行文件; class CActiveXDocTemplate : public CSingleDocTemplate { enum { IDR_NOTUSED 0x7FFF }; CWnd* m_pParentWnd; CFrameWnd* m_pFrameWnd; C…
常见存储过程分页PK赛——简单测试分析常见存储过程分页速度
数据的分页是我们再熟悉不过的功能了,各种各样的分页方式层出不穷。今天我把一些常见的存储过程分页列出来,再简单地测一下性能,算是对知识的总结,也是对您好想法的抛钻引玉。废话不多说,开始吧~~ 1.首先建立一张测试表…

YOLOv3模型剪枝,瘦身80%,提速100%,精度基本不变
作者 | CV君转载自我爱计算机视觉(ID: aicvml)如果要在实际应用中部署目标检测,你会想到哪项算法?在52CV目标检测交流群里,被提及最多的,恐怕就是YOLOv3了。虽然新出的一些算法号称“完胜”“吊打”某某某算…

Ubuntu开发用新机安装流程
1.SSH安装 Ubuntu缺省已安装客户端,此处安装服务端 sudo apt-get install openssh-server 确认sshserver是否启动 netstat -tlp | grep ssh 或 ps -e | grep ssh 未启动,选择启动 sudo /etc/init.d/ssh start 2.问题解决:ACPI Error:Method p…

人工智能六十年技术简史
出品 | AI科技大本营(ID:rgznai100)作者:李理,环信人工智能研发中心vp,十多年自然语言处理和人工智能研发经验。主持研发过多款智能硬件的问答和对话系统,负责环信中文语义分析开放平台和环信智能机器人的设…

【Android游戏开发二十五】在Android上的使用《贝赛尔曲线》!
首先对于《赛贝尔曲线》不是很了解的童鞋,请自觉白度百科、google等等... 为了方便偷懒的童鞋,这里给个《贝赛尔曲线》百科地址,以及一段话简述《贝赛尔曲线》: 《贝赛尔曲线》白度百科快速地址:http://baike.baidu.co…

Spring Boot 工程集成全局唯一ID生成器 Vesta
2019独角兽企业重金招聘Python工程师标准>>> 本文内容脑图如下: 文章共 760字,阅读大约需要 2分钟 ! 概 述 在前一篇文章 《Spring Boot工程集成全局唯一ID生成器 UidGenerator》 中给大家推荐了一款由百度开发的基于 Snowflake算…

vs2008中,创建基于对话框的mfc动态库步骤
1、利用MFC Dll向导初始生成一个mfc dll(默认设置); 2、添加一个对话框资源; 3、向工程中添加一个.h、.cpp文件,作为外部的接口; 4、.h头文件的格式仿照于基于控制台的dll的头文件格式; 5、.h头文件中包括资源文件头文…

poj3468 A Simple Problem with Integers
http://acm.hust.edu.cn:8080/judge/problem/viewProblem.action?id14607 题意:题目给你n个数,m个操作,接下来一行给你这n个数,接下的几行给出m个操作,Q a b 表示查询区间[a,b]里的数和和。U a b c 表示把区间[a,b]里的数都加上c…

【Luogu】P1613 跑路
【Luogu】P1613 跑路 一、题目 题目描述 小A的工作不仅繁琐,更有苛刻的规定,要求小A每天早上在6:00之前到达公司,否则这个月工资清零。可是小A偏偏又有赖床的坏毛病。于是为了保住自己的工资,小A买了一个十分牛B的空间…

matlab图形用户界面设计简介
1、File->New->GUI->Create New GUI->Blank GUI->OK即可打开图形用户界面开发环境。 在里面可以拖放需要的控件,包括pushbutton、slider、radiobutton、togglebutton、checkbox、listbox、popupmenu、edit text、static text、table、axes、panel、…

旷视发布《人工智能应用准则》,倡导AI技术健康可持续发展
2019年7月8日,旷视宣布推出基于企业自身管理标准的《人工智能应用准则》(以下简称《准则》),旨在从人工智能企业自身的角度,规范、引导人工智能技术正确运用和健康发展,并确保其安全可控可靠,促…

Java知识积累——String引用的判断问题
看如下程序 1 public static void main(String[] args) {2 String a new String("abc");3 String b new String("abc");4 System.out.println(a b); 5 6 String c "abc";7 String d "abc";8 …

windows7下vs2008常见错误解决方法汇总
1、fatal error LNK1000:Internal error during IncrBuildImage 解决方法:选中对应工程-->点击右键,选择Properties-->Configuration Properties-->Linker-->General-->选中Enable Incremental Linking:改为No(/INCREMENTAL:NO),原始选项…

5G对AIoT的作用并无夸大,最大价值在于融合
采访嘉宾 | 崔宝秋、高恩重整理 | 夕颜出品 | AI科技大本营(ID:rgznai100)近年来,AIoT 的概念非常火爆,有不少企业将 AIoT 提升到公司的战略发展高度,然而实际上,走进普通人日常生活并真正实用的 AIoT 产品…