WaitForMultipleObjects函数

转载 2011年01月15日 00:48:00
WaitForMultipleObjects函数解释及其用法
2009-04-24 11:29

 

 
函数原型:
DWORD WaitForMultipleObjects(
DWORD nCount, // number of handles in array
CONST HANDLE *lpHandles, // object-handle array
BOOL bWaitAll, // wait option
DWORD dwMilliseconds // time-out interval
);

WaitForMultipleObjects函数用于等待多个内核对象,前两个参数分别为要等待的内核对象的个数和句柄数组指针。如果将第三个参数bWaitAll的值设为TRUE,等待的内核对象全部变成受信状态以后此函数才返回。否则,bWaitAll0的话,只要等待的内核对象中有一个变成了受信状态,WaitForMultipleObjects就返回,返回值指明了是哪一个内核对象变成了受信状态。

实例一:

下面的代码说明了函数返回值的作用:

         HANDLE h[2];

         h[0] = hThread1;

         h[1] = hThread2;

         DWORD dw = ::WaitForMultipleObjects(2, h, FALSE, 5000);

         switch(dw)

         {       case WAIT_FAILED:

                            // 调用WaitForMultipleObjects函数失败(句柄无效?)

                            break;

                   case WAIT_TIMEOUT:

                            // 5秒内没有一个内核对象受信

                            break;

                   case WAIT_OBJECT_0 + 0:

                            // 句柄h[0]对应的内核对象受信

                            break;

                   case WAIT_OBJECT_0 + 1:

                            // 句柄h[1]对应的内核对象受信

                            break;

         }

参数bWaitAllFALSE的时候,WaitForMultipleObjects函数从索引0开始扫描整个句柄数组,第一个受信的内核对象将终止函数的等待,使函数返回。

实例二:

for(int i=0;i<6;i++)
{
   for(int j=0;j<10;j++)
   {
    theport[j].rmt_host=rmt_host;
    theport[j].p=port[i*10+j];
    theport[j].n=j;
    Thread[j]=AfxBeginThread(pScan,(LPVOID)&theport[j]);
    hThread[j]=Thread[j]->m_hThread;
    Sleep(1);
   }
   WaitForMultipleObjects(10,hThread,TRUE,120000);
}

注:线程退出后,即线程对象计数值变为0后,线程才会变为受信状态。

 

 

 

 

 

WaitForMultipleObjects用法探索

WaitForMultipleObjectsWindows中的一个功能非常强大的函数,几乎可以等待Windows中的所有的内核对象(关于该函数的描述和例子见MSDN,)。但同时该函数在用法上却需要一定的技巧。
                       

原型DWORD WaitForMultipleObjects(        
 DWORD nCount,                   
 const HANDLE* lpHandles,                     
 BOOL bWaitAll,                 
 DWORD dwMilliseconds               
);

                       

 
                       

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

问题就在这里,我们如何可以获取所有被同时触发的内核对象。举个例子:我们需要在一个线程中处理从完成端口、数据库、和可等待定时器来的数据。一个典型的实现方法就是:用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)

                {

                    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;

}


                       

评论 (1)

parsen christion 的图片
parsen christion - 2008年 11 月 21 日
函数WaitForMultipleObjects整理
DWORD WaitForMultipleObjects(  DWORD nCount,  const HANDLE* lpHandles,  BOOL bWaitAll,  DWORD dwMilliseconds);
其中参数
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) //所有事件发生
 {
  //所有的信号量都有效时(事件都发生)其中之一无效。
 }
 else if (nIndex == WAIT_TIMEOUT) //超时500毫秒 
{   //超时可作定时用  }
 }
return 0L;}
必须同时执行以下两个事件才可以(只执行一个无效)
SetEvent(m_hEvent[0]);
SetEvent(m_hEvent[1]);

关于afxbeginthread时WaitForMultipleObjects不起作用

afxbeginthread时,对这个方法蛮感兴趣的,创建线程很方便,但是我注意了下,该函数返回的不是创建线程的句柄,而是cwndthread的指针对象,而我想用WaitForMultipleObje...
  • liujiayu2
  • liujiayu2
  • 2014年11月27日 19:42
  • 615

关于mfc里afxbeginthread的一些感悟

      最近看一本书,书写的不错,很通俗易懂,我对其中的一些例子自己也做了练习,学到了不少.在我看线程这一块时,还是有不少感悟.        在看到afxbeginthread时,对这个方法蛮感...
  • sx1989827
  • sx1989827
  • 2009年02月02日 18:58
  • 6928

MFC 主界面函数中线程等待避免界面卡死的处理方法

实用场景: 例如在MFC主界面某个Button Click事件中起一个线程去做处理一些事情,在起的线程运行完毕后,接着跑Click起线程后的代码,已达到按顺序执行,保证时许正确的目的。 问...
  • xl19900502
  • xl19900502
  • 2015年12月17日 15:09
  • 5777

AfxBeginThread第二个参数LPVOID pParam的使用

今天使用AfxBeginThread()中第个参数LPVOID pParam的使用
  • wawa1203
  • wawa1203
  • 2014年06月04日 11:18
  • 1492

AfxEndThread导致内存泄露

[cpp] view plain copy UINT WorkingProc(LPVOID pParam)   {       CString strFolderPath = _T("....
  • qq_23992597
  • qq_23992597
  • 2016年07月05日 14:14
  • 1112

WaitForMultipleObjects用法详解,一看就懂

WaitForMultipleObjects是Windows中的一个功能非常强大的函数,几乎可以等待Windows中的所有的内核对象 WAIT_ABANDONED_0:所有对象都发出消息,而且其中...
  • sac761
  • sac761
  • 2016年09月07日 09:16
  • 13662

WaitForSingleObject与WaitForMultipleObjects用法详解

等待某一线程完成了再继续做其他事情,要实现这个目的,可以使用Windows API函数WaitForSingleObject,或者WaitForMultipleObjects。这两个函数都会等待Obj...
  • makenothing
  • makenothing
  • 2016年04月20日 09:13
  • 3925

_beginthreadex与createthread和AfxBeginThread的区别

1、不要在一个MFC程序中使用_beginthreadex()或CreateThread()。  这句话的意思是由于AfxBeginThread()是MFC封装的启动线程的函数,里面包含了很多和MF...
  • sptoor
  • sptoor
  • 2011年11月21日 11:02
  • 2131

CreateThread, AfxBeginThread,_beginthread, _beginthreadex的区别

一、转载自: http://www.cnblogs.com/chuncn/archive/2009/03/08/1406096.htmlCreateThread是Windows的API函数(SDK函数...
  • miyunhong
  • miyunhong
  • 2009年09月29日 13:57
  • 1771

WaitForMultipleObjects返回错误码87

近期做写demo做测试的时候,因为有个功能是要到国外服务器请求登陆,授权,请求metadata,通过之后又会在国内的服务器上下载文件,这种情况,网络表示很无语。 请求文件的metadata数量众多,...
  • sepnineth
  • sepnineth
  • 2016年01月05日 15:05
  • 508
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:WaitForMultipleObjects函数
举报原因:
原因补充:

(最多只允许输入30个字)