关闭

WaitForMultipleObjects函数

标签: objectsemaphorewinapinullthreadfunction
1288人阅读 评论(0) 收藏 举报
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]);
0
0

查看评论
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
    个人资料
    • 访问:1326786次
    • 积分:11854
    • 等级:
    • 排名:第1253名
    • 原创:58篇
    • 转载:526篇
    • 译文:2篇
    • 评论:57条
    文章分类
    最新评论