waitformultipleobject函数的使用,

  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的观点,版权归原作者所有,仅为传播更多信息之目的,如有侵权请联系,我们将第一时间修改或删除,多谢。

留言与评论(共有 条评论)
   
验证码: