waitformultipleobject函数的使用,
来自:http://blog . . net/byxdaz/article/details/5638680
用户态线程同步机制是高效的。如果需要考虑线程同步,首先要考虑用户态的线程同步方法。但是用户态的线程同步是有限的,用户态的线程同步方法对于多个进程间的线程同步是无能为力的。此时只能考虑内核模式。
用户态与内核态线程同步机制的比较:
线程同步机制很慢。
线程必须从用户模式更改为内核模式。这种转换代价很大:在x 8 6平台上,一次往返大约需要1000个C P U周期。
Windows提供了许多内核对象来同步线程。对于线程同步来说,这些内核对象有两个非常重要的状态:“通知”状态和“未通知”状态(也译为:可信状态和不可信状态)。Windows提供了几个可以处于通知状态和未通知状态的内核对象:进程、线程、作业、文件、控制台输入/输出/错误流、事件、等待计时器、信号量、互斥体。
您可以通知一个内核对象处于“通知状态”,然后让等待该内核对象的其他线程继续执行。您可以使用Windows提供的API函数和wait函数来等待一个或一些内核对象得到通知。
I. WaitForSingleObject,WaitForMulitpleObjects
函数:等待内核对象被通知。
您可以使用WaitForSingleObject函数来等待内核对象得到通知:
DWORD WaitForSingleObject(
HANDLE hObject,//表示内核对象的句柄。
DWORD毫秒);//等待时间
这个函数需要传递一个内核对象句柄,它标识一个内核对象。如果内核对象处于无通知状态,这个函数会导致线程进入阻塞状态;如果内核对象处于通知状态,该函数立即返回WAIT_OBJECT_0。第二个参数表示等待时间(毫秒),您可以传递INFINITE来表示您希望无限期等待。如果第二个参数为0,该函数将测试同步对象的状态并立即返回。如果等待超时,该函数将返回WAIT_TIMEOUT。如果函数失败,它将返回WAIT_FAILED。可以通过下面的代码来判断:
DWORD dw=WaitForSingleObject(h process,5000);//等待进程完成
开关(dw)
{
案例等待_对象_0:
//h process表示的进程在5秒后结束
打破;
案例等待_超时:
//等待5秒以上
打破;
案例等待_失败:
//函数调用失败,比如传递无效句柄。
打破;
}
您还可以使用WaitForMulitpleObjects函数来等待多个内核对象得到通知:
DWORD WaitForMultipleObjects(
Orddw dwcount,//等待的内核对象数
CONST HANDLE * phObjects,//保存要等待的内核对象句柄的数组。
Boobwaitall,//是否要等到所有内核对象都处于通知状态后再返回?
DWORD毫秒);//等待时间
该函数的第一个参数表示等待的内核对象的数量,可以是0到MAXIMUM_WAIT_OBJECTS(64)之间的一个值。phObjects参数是一个保存等待的内核对象句柄的数组。如果bWaitAll参数为TRUE,则只有当所有等待的内核对象都处于通知状态时,函数才会返回;如果为FALSE,只要有一个内核对象处于通知状态,该函数就会返回。第四个参数类似于WaitForSingleObject中的dwMilliseconds参数。
函数失败并返回WAIT _ FAILED;如果超时,则返回WAIT _ TIMEOUT;如果bWaitAll参数为TRUE,则函数成功返回WAIT _ OBJECT _ 0;如果bWaitAll为FALSE,该函数将返回一个值,指示哪个内核对象收到了通知。
您可以按如下方式使用该功能:
手柄h[3];//句柄数组
//三个进程句柄
h[0]=hprocess 1;
h[1]=hprocess 2;
h[2]=hprocess 3;
DWORD dw=WaitForMultipleObjects(3,h,FALSE,5000);//等待3个进程完成
开关(dw)
{
案例等待_失败:
//函数调用失败
打破;
案例等待_超时:
//超时
打破;
案例等待_对象_0 0:
//h[0](h process 1)表示的进程结束。
打破;
案例等待_对象_0 1:
//h[1](h process 2)表示的进程结束。
打破;
案例等待_对象_0 2:
//h[2](h process 3)表示的进程结束。
打破;
}
您也可以在等待另一个内核对象的同时通知另一个内核对象。这两个操作以原子方式执行:
DWORD信号对象和等待(
处理hObjectToSignal,//通知的内核对象
HandleHobjectToAiton,//等待内核对象
Ord百万dw,//等待时间
BOOL bAlertable);//暂时不讨论IO完成端口相关的参数。
这个函数在内部使hObjectToSignal参数指示的内核对象成为被通知状态,同时等待hObjectToWaitOn参数表示的内核对象。dwMilliseconds参数的用法类似于WaitForSingleObject函数。
该函数返回以下内容:WAIT_OBJECT_0、WAIT_TIMEOUT、WAIT_FAILED、WAIT_IO_COMPLETION。
当你需要通知一个互斥内核对象并等待一个事件内核对象时,你可以这样写:
release mutex(hMutex);
WaitForSingleObject(hEvent,INFINITE);
然而,这样的代码不能以原子的方式操作这两个内核对象。因此,可以对其进行如下更改:
SignalObjectAndWait(hMutex,hEvent,INFINITE,FALSE);
二。MsgWaitForMultipleObjects
功能:屏蔽时仍可回复消息。
MsgWaitForMultipleObjects()函数类似于WaitForMultipleObjects(),但它会在“对象被激发”或“消息到达队列”时唤醒并返回。MsgWaitForMultipleObjects()接收另一个参数,该参数允许您指定观察哪些消息。
DWORD MsgWaitForMultipleObjects(
Ordncount,//表示pHandles指向的handles数组中的元素个数,最大容量为MAXIMUM_WAIT_OBJECTS。
LPHANDLE phandles,//指向一个对象句柄数组,这些句柄不必属于同一类型。
Boofwaitall,//是否要等待所有句柄都被激发后再返回?
DWORD毫秒,///超时
Ord dwwakemask//要观察的用户输入消息的类型
);
参数
dwWakeMask
要观察的用户输入消息的类型:值含义
QS事件输入,WM _定时器,WM _画图,WM _热键,或张贴的消息在队列中。
QS_ALLINPUT队列中的任何消息。
QS_ALLPOSTMESSAGE一个已发布的消息(除了这里列出的以外)在队列中。
QS热键一个WM热键消息在队列中。
QS输入一个输入消息在队列中。
QS _ KEY WM _ KEYUP、WM_KEYDOWN、WM_SYSKEYUP或WM_SYSKEYDOWN消息在队列中。
一个WM_MOUSEMOVE消息或鼠标按钮消息(WM_LBUTTONUP、WM_RBUTTONDOWN等等)。
一个鼠标按钮消息(WM_LBUTTONUP,WM_RBUTTONDOWN,等等)。
一个WM_MOUSEMOVE消息在队列中。
一个WM_PAINT消息在队列中。
QS_POSTMESSAGE一个已发布的消息(除了那些刚刚列出的)在队列中。
另一个线程或应用程序发送的消息在队列中。
QS定时器一个WM定时器消息在队列中
返回值
WAIT_TIMEOUT:由于时间结束而返回。
WAIT_OBJECT_0:当bWaitAll为真时
WAIT _ OBJECT _ 0to(WAIT _ OBJECT _ 0n count1):bwaital为FALSE。用wait _ object _ 0减去返回值,数组中哪个句柄被触发。
wait _ abused _ 0to(wait _ abused _ 0n count1):等待对象中有任何互斥体。
WAIT_FAILED:该值在函数失败时返回。可以使用GetLastError()找出失败的原因。
WAIT_OBJECT_0 nCount:消息到达队列。
使用MsgWaitForMultipleObjects()的正确方法是重写主消息循环,以便可以像处理消息一样处理触发器。通常程序中只有一个地方调用MsgWaitForMultipleObjects(),这个调用存在于消息循环中。
注意:
1.收到WM_QUIT后,Windows还是会给你发消息。如果你想在收到WM_QUIT后等待所有线程结束,你必须继续处理你的消息,否则窗口会变得没有反应,也没有能力重绘。
2.MsgWaitForMultipleObjects()不允许句柄数组中有间隔。因此,在触发句柄时,应该在下次调用MsgWaitForMultipleObjects之前对句柄数组进行排序和压缩,而不是只将数组中的句柄设置为NULL。
3.如果另一个线程更改了对象数组,而这正是您所期待的,那么就需要一种方法来强制MsgWaitForMultipleObjects返回并重新开始以包含新的句柄。
三。MsgWaitForMultipleObjectsEx
功能:屏蔽时仍可回复消息。
功能原型
DWORD MsgWaitForMultipleObjectsEx(
Ordncount,//句柄数组中的句柄数量
LPHANDLE pHandles,//指向句柄数组的指针
Ord dw毫秒,//超时值以毫秒为单位
Ord dwwakemask,//等待的输入事件的类型
orddwflags//等待标志
);
参数
NCount,指定pHandles指向的数组中对象句柄的数量。对象的最大数量是MAXIMUM_WAIT_OBJECTS-1。
指向一个对象句柄数组。有关可以使用的对象句柄类型的列表,请查看备注部分。一个数组可以包含多种对象类型。Windows:数组中的句柄必须具有同步访问权限。有关更多信息,请参见MSDN的标准访问权限。
DwMilliseconds,以毫秒为单位指定超时值。即使不满足参数dwWakeMask和dwFlags中指定的条件,该函数仍会在超时后返回。如果dwMilliseconds值为0,该函数测试指定的对象状态并立即返回。如果dwMilliseconds值为无穷大,则函数超时时间为无穷大。
DwWakeMask,指定添加到对象句柄数组的输入事件对象句柄的对象类型。该参数可以是下列值的任意组合:
价值意义
QS事件
WM_TIMER、WM_PAINT、WM_HOTKEY输入消息或发布的消息在消息队列中。
QS _阿林普特
消息队列中有任何消息
QS所有邮件
已注册的消息(此处列出的除外)在消息队列中。
QS _热键
WM_HOTKEY消息在消息队列中
QS _输入
输入消息在消息队列中。
QS _基
Wm _ keyup、WM _ keydown、WM _ syskeyup或WM_SYSKEYDOWN消息在消息队列中。
QS _鼠标
WM_MOUSEMOVE消息或鼠标点击消息(WM_LBUTTONUP、WM_RBUTTONDOWN等。)在消息队列中。
QS _鼠标按钮
鼠标点击消息(WM_LBUTTONUP,WM_RBUTTONDOWN等。)在消息队列中。
QS _鼠标移动
WM_MOUSEMOVE消息在消息队列中
QS _油漆
WM_PAINT消息在消息队列中
QS邮件
已注册的消息(此处列出的除外)在消息队列中。
QS _发送消息
由另一个线程或应用程序发送的消息在消息队列中。
QS计时器
WM_TIMER消息在消息队列中
DwFlags,指定等待类型。该参数可以是下列值的任意组合:
价值意义
0
当任何一个对象变成信号状态时,函数返回。返回值指示哪个对象状态更改导致函数返回。
MWMO_WAITALL
只有当pHandles数组中的所有对象都有信号时,该函数才返回。
MWMO_ALERTABLE
调用QueueUserAPC加入APC将导致函数返回
MWMO _可用
仅适用于Windows 98、Windows NT 5.0及更高版本:存在于消息队列中的输入函数将返回,即使该输入已被另一个函数检测到,如PeekMessage函数。
返回值
如果函数成功,返回值指示导致函数返回的事件。成功的函数值是下列值之一:
价值意义
WAIT_OBJECT_0到(WAIT_OBJECT_0 nCount-1)
如果设置了MWMO_WAITALL标志,返回值表明所有指定的对象都处于信号状态。返回值减去WAIT_OBJECT_0就是pHandles数组中导致函数返回的对象的索引。
等待_对象_0计数
dwWakeMask参数中指定的新输入类型存在于输入队列中。peekmessage、getmessage、getqueuestatus和WaitMessage等函数将队列中的消息标记为旧消息。因此,当您在这些函数之后调用MsgWaitForMultipleObjectsEx时,除非新的指定输入到达,否则这些函数不会返回。当需要该线程活动的系统事件发生时,也将返回该值,例如前台活动。因此,即使没有相应的输入或dwWaitMask设置为0,msgwaitmask也可以返回。如果发生这种情况,应在再次调用MsgWaitForMultipleObjectsEx之前调用PeekMessage或GetMessage来处理系统事件。
等待_放弃_0到(等待_放弃_ 0n计数-1)
如果设置了MWMO_WAITALL标志,返回值表明所有指定的对象都处于有信号状态,并且其中至少有一个是被放弃的互斥体。此外,返回值减去WAIT _ discarded _ 0就是导致函数返回的pHandles数组中被丢弃的互斥体的索引。
等待_ IO _完成
被等待加入队列的用户模式异步过程调用(APC)终止。
等待_超时
超时,但不满足dwFlags和dwWakeMask参数中的条件
如果函数调用失败,返回值为0xFFFFFFFF。要获得更多错误信息,请调用GetLastError函数。
评论
MsgWaitForMultipleObjectsEx函数检测是否满足dwWakeMask和dwFlags参数中指定的条件。如果条件不满足,调用线程进入高效等待状态。当一个线程等待满足其中一个等待条件或超时时,只需要很少的处理器时间。
在返回之前,wait函数会修改一些异步对象的状态。修改将只针对那些在信号状态被设置后将导致函数返回的对象。例如,系统会将信号对象的引用计数减一。当dwFlags为零,多个对象处于信号状态时,函数选择其中一个对象保证等待;未选定对象的状态不受影响。
MsgWaitForMultipleObjectsEx函数可以在pHandles数组中指定以下对象类型:
变更通知(变更通知)
控制台输入
事件
工作(工作)
互相排斥
过程
信号
线
等待计时器
请参阅同步对象了解详情。
消除时,QS _所有邮件和QS _邮件标志是不同的。当您调用GetMessage或PeekMessage时,无论您是否过滤消息,QS_POSTMESSAGE都会被删除。当调用不过滤消息的GetMessage或PeekMessage(wMsgFilterMin和wMsgFilterMax都为零)时,QS_ALLPOSTMESSAGE被消除。这在多次调用PeekMessage以从不同区域获取消息时非常有用。
Windows CE:Windows CE不支持QS _热键分配dwWakeMask参数,也不支持MWMO_WAITALL和MWMO_ALERTABLE标志分配dwFlags参数。
MsgWaitForMultipleObjectsEx复制句柄表,向其中添加消息队列事件,然后调用WaitForMultipleObjects。
示例代码片段
//一段代码,等待线程和事件对象和消息,超时值2000毫秒。
CWinThread * pThread=AfxBeginThread((AFX _ thread proc)YourThreadFun,NULL);
处理hThreadAndEvent[2];
hThreadAndEvent[0]=pThread-m _ hThread;
hThreadAndEvent[1]=:create event(NULL,FALSE,FALSE,NULL);
DWORD dw return=:MsgWaitForMultipleObjectsEx(2,
hThreadAndEvent,
2000,//每2秒醒来一次。
QS事件,
MWMO _可用
);
if ( dwReturn==WAIT_OBJECT_0)
{
//线程对象通知
}
if ( dwReturn==WAIT_OBJECT_0 1)
{
//事件对象通知
}
if ( dwReturn==WAIT_OBJECT_0 2)
{
//消息
}
if ( dwReturn==WAIT_TIMEOUT)
{
//超时
}
郑重声明:本文由网友发布,不代表盛行IT的观点,版权归原作者所有,仅为传播更多信息之目的,如有侵权请联系,我们将第一时间修改或删除,多谢。