请教WaitForMultipleObjects不同时等待多于64个且返回正确事件索引的思路?

mkelehk 2015-04-20 05:17:28
现在遇到一个问题:需要等待的事件最多是256,但有可能小于64。使用WaitForMultipleObjects(n,n_event,FALSE, INFINITE);的话小于64个正常,大于时返回-1。
网上大多数是”同时“等待多于64个事件(bWaitAll =TRUE),我想等待多于64个事件但不需要“同时”(bWaitAll =FALSE),有其中一个事件等到了就返回,多个事件同时等到时返回最小序号,有什么策略?
我现在是开了4个线程,在主线程上判断当前等待的事件是否0<n<=64,64<n<=128,128<n<=192和192到256等进行分组。根据这几种情况开放第几个线程:假如线程1是等待<=64个事件的,线程2是用于等待>64且<=128个事件的,线程3和4类推,当主线程判断出事件属于64<n<=128,则SetEvent让线程1和线程2都导通。线程1用WaitForMultipleObjects等待前64个事件,而线程2等待剩下的事件。等到事件标志后setEvent同步主线程,让主线程继续向下执行。但发现,返回值比较乱,且线程2永远进不去。
下面是代码片段
//主线程上
其中lpHandles是一个装载nCount个事件的数组。

...
if(nCount>64 && nCount<=128)
{
hGroupEvent.GroupEvent2.nEvent=nCount-64;
memcpy(hGroupEvent.GroupEvent2.reg_event,lpHandles+64,hGroupEvent.GroupEvent2.nEvent*sizeof(void *));
hGroupEvent.GroupEvent1.nEvent=64;
memcpy(hGroupEvent.GroupEvent1.reg_event,lpHandles,hGroupEvent.GroupEvent1.nEvent*sizeof(void *));
SetEvent(hWFMO.g_hEvent1);
SetEvent(hWFMO.g_hEvent2);
...
WaitForSingleObject(hWFMO.g_hRegEvent,INFINITE);
... //继续处理

//各等待子线程

...
static void __stdcall WFMO_Thread1(void)
{
while(IsStart)
{
WaitForSingleObject(hWFMO.g_hEvent1,INFINITE);
hWFMO.ret=WaitForMultipleObjects(hGroupEvent.GroupEvent1.nEvent,hGroupEvent.GroupEvent1.reg_event,FALSE, INFINITE);
hGroupEvent.GroupEvent1.nEvent=0;
SetEvent(hWFMO.g_hRegEvent);
}
}
static void __stdcall WFMO_Thread2(void)
{
while(IsStart)
{
WaitForSingleObject(hWFMO.g_hEvent2,INFINITE);
...
hWFMO.ret=WaitForMultipleObjects(.....);
SetEvent(hWFMO.g_hRegEvent);
}
}
...
...全文
556 9 打赏 收藏 转发到动态 举报
写回复
用AI写文章
9 条回复
切换为时间正序
请发表友善的回复…
发表回复
牧童吃五谷 2015-11-04
  • 打赏
  • 举报
回复
1.按照你的程序建议开5个线程,并且额外增加一个信号量; 2.其中四个线程在等待那个256个信号量,第5个线程在等待额外增加的一个信号量。 3在4个等待多信号的线程中,如果发现了一个信号量,则把该信号量的索引号(0~255)保存到到一个整数中,并且给额外增加的信号量发信号 //不过我建议编写程序不要开启等待256个信号量,建议修改程序结构
  • 打赏
  • 举报
回复
决定用这个编辑器的人绝对是很大的大傻B; 1.头文件(WaitForMultiEx.h) DWORD WINAPI WaitForMultipleExpressions(DWORD nExpObjects,const HANDLE* phExpObjects,DWORD dwMilliSeconds); 2.源文件(WaitForMultiEx.cpp) #define _WIN32_WINNT 0x0403 #include<windows.h> #include<process.h> #include<malloc.h> #include "WaitForMultiEx.h" #define ERROR_SELECT_TOO_LONG 32766 #define ERROR_TOO_MANY_SELECTS 32767 typedef struct{ DWORD nExpObjects; HANDLE *phExpObjects; }EXPRESSION,*LPEXPRESSION; unsigned __stdcall WFME_ExpressionThread(void *lpParam) { //wait for all of kernel objects in a expression to be signaled or a APC to be added to APC Queue in a thread LPEXPRESSION lpExpression=(LPEXPRESSION)lpParam; WaitForMultipleObjectsEx(lpExpression->nExpObjects,lpExpression->phExpObjects,true,INFINITE,true); return 0; } void CALLBACK WFME_ExpressionAPC(ULONG_PTR dwParam) { //only add it to a thread`s APC Queue to stop thread`s waiting } DWORD WINAPI WaitForMultipleExpressions(DWORD nExpObjects,const HANDLE* phExpObjects,DWORD dwMilliSeconds) { //wait for a group of expressions //if one expression which a group of kernel objects in is signaled,the function return //if the first expressiont is satisfied,the function return WAIT_OBJECT_0, //if the second expression is satisfied,the function return WAIT_OBJECT_1, //and so on... //the format of the handle array named phExpObjects: //1.each expression is separated by NULL //2.it`s not more than 63 object handles in a expression //3.it`s not more than 64 expressions in the handle array EXPRESSION Expressions[MAXIMUM_WAIT_OBJECTS]; HANDLE *phExpObjectsTmp,ahThreads[MAXIMUM_WAIT_OBJECTS]; //allocate the space on stack phExpObjectsTmp=(HANDLE*)_alloca((nExpObjects+1)*sizeof(HANDLE)); CopyMemory(phExpObjectsTmp,phExpObjects,nExpObjects*sizeof(HANDLE)); phExpObjectsTmp[nExpObjects]=NULL; DWORD dwRet=0; DWORD NumExps=0,ExpsNum=0; DWORD BeginPos=0,CurPos=0; HANDLE hSemOnlyOne; hSemOnlyOne=CreateSemaphore(NULL,1,1,NULL); //create a semaphore to add it to the NULL handle position in phExpObjectsTmp array while(dwRet!=WAIT_FAILED&&CurPos<=nExpObjects){ //ReSolve the phExpObjectsTmp Array while(phExpObjectsTmp[CurPos]!=NULL) CurPos++; phExpObjectsTmp[CurPos]=hSemOnlyOne; Expressions[NumExps].phExpObjects=&phExpObjectsTmp[BeginPos]; Expressions[NumExps].nExpObjects=CurPos-BeginPos+1; if(Expressions[NumExps].nExpObjects>MAXIMUM_WAIT_OBJECTS){ dwRet=WAIT_FAILED; SetLastError(ERROR_SELECT_TOO_LONG); } BeginPos=++CurPos; if(++NumExps>=MAXIMUM_WAIT_OBJECTS&&CurPos<=nExpObjects){ dwRet=WAIT_FAILED; SetLastError(ERROR_TOO_MANY_SELECTS); } } if(dwRet!=WAIT_FAILED){ //the format of the handle array named phExpObjects is correct unsigned int dwThreadId; for(ExpsNum=0;ExpsNum<NumExps;ExpsNum++) ahThreads[ExpsNum]=(HANDLE)_beginthreadex(NULL,0,WFME_ExpressionThread,(void*)&Expressions[ExpsNum],0,&dwThreadId); dwRet=WaitForMultipleObjects(NumExps,ahThreads,false,dwMilliSeconds); //wait for one of threads to be signaled if(dwRet==WAIT_TIMEOUT){ dwRet=WaitForSingleObject(hSemOnlyOne,0); if(dwRet==WAIT_TIMEOUT){ //one expression is satisfied dwRet=WaitForMultipleObjects(NumExps,ahThreads,false,INFINITE); } else{ //no expression is satisfied dwRet=WAIT_TIMEOUT; } } for(ExpsNum=0;ExpsNum<NumExps;ExpsNum++){ //stop the rest threads` waiting by add APC to their APC Queues if(dwRet==WAIT_TIMEOUT||(dwRet-WAIT_OBJECT_0)!=ExpsNum) QueueUserAPC(WFME_ExpressionAPC,ahThreads[ExpsNum],0); CloseHandle(ahThreads[ExpsNum]); } } return dwRet; }
  • 打赏
  • 举报
回复
核心编程里实现的WaitForMultipleExpressions函数;

WaitForMultiEx.h
DWORD WINAPI WaitForMultipleExpressions(DWORD nExpObjects,const HANDLE* phExpObjects,DWORD dwMilliSeconds);
WaitForMultiEx.cpp
#define _WIN32_WINNT 0x0403
#include<windows.h>
#include<process.h>
#include<malloc.h>
#include "WaitForMultiEx.h"
#define ERROR_SELECT_TOO_LONG 32766
#define ERROR_TOO_MANY_SELECTS 32767
typedef struct{
    DWORD nExpObjects;
    HANDLE *phExpObjects;
}EXPRESSION,*LPEXPRESSION;
unsigned __stdcall WFME_ExpressionThread(void *lpParam)
{
    //wait for all of kernel objects in a expression to be signaled or a APC to be added to APC Queue in a thread
    LPEXPRESSION lpExpression=(LPEXPRESSION)lpParam;
    WaitForMultipleObjectsEx(lpExpression->nExpObjects,lpExpression->phExpObjects,true,INFINITE,true);
    return 0;
}
void CALLBACK WFME_ExpressionAPC(ULONG_PTR dwParam)
{
    //only add it to a thread`s APC Queue to stop thread`s waiting
}
DWORD WINAPI WaitForMultipleExpressions(DWORD nExpObjects,const HANDLE* phExpObjects,DWORD dwMilliSeconds)
{
    //wait for a group of expressions
    //if one expression which a group of kernel objects in is signaled,the function return
    //if the first expressiont is satisfied,the function return WAIT_OBJECT_0,
    //if the second expression is satisfied,the function return WAIT_OBJECT_1,
    //and so on...
    //the format of the handle array named phExpObjects:
    //1.each expression is separated by NULL
    //2.it`s not more than 63 object handles in a expression
    //3.it`s not more than 64 expressions in the handle array
    EXPRESSION Expressions[MAXIMUM_WAIT_OBJECTS];
    HANDLE *phExpObjectsTmp,ahThreads[MAXIMUM_WAIT_OBJECTS];
    //allocate the space on stack
    phExpObjectsTmp=(HANDLE*)_alloca((nExpObjects+1)*sizeof(HANDLE));
    CopyMemory(phExpObjectsTmp,phExpObjects,nExpObjects*sizeof(HANDLE));
    phExpObjectsTmp[nExpObjects]=NULL;
    DWORD dwRet=0;
    DWORD NumExps=0,ExpsNum=0;
    DWORD BeginPos=0,CurPos=0;
    HANDLE hSemOnlyOne;
    hSemOnlyOne=CreateSemaphore(NULL,1,1,NULL); //create a semaphore to add it to the NULL handle position in phExpObjectsTmp array
    while(dwRet!=WAIT_FAILED&&CurPos<=nExpObjects){
        //ReSolve the phExpObjectsTmp Array 
        while(phExpObjectsTmp[CurPos]!=NULL)
            CurPos++;
        phExpObjectsTmp[CurPos]=hSemOnlyOne; 
        Expressions[NumExps].phExpObjects=&phExpObjectsTmp[BeginPos];
        Expressions[NumExps].nExpObjects=CurPos-BeginPos+1;
        if(Expressions[NumExps].nExpObjects>MAXIMUM_WAIT_OBJECTS){
            dwRet=WAIT_FAILED;
            SetLastError(ERROR_SELECT_TOO_LONG);
        }
        BeginPos=++CurPos;
        if(++NumExps>=MAXIMUM_WAIT_OBJECTS&&CurPos<=nExpObjects){
            dwRet=WAIT_FAILED;
            SetLastError(ERROR_TOO_MANY_SELECTS);
        }
    }
    if(dwRet!=WAIT_FAILED){
        //the format of the handle array named phExpObjects is correct
        unsigned int dwThreadId; 
        for(ExpsNum=0;ExpsNum<NumExps;ExpsNum++)
            ahThreads[ExpsNum]=(HANDLE)_beginthreadex(NULL,0,WFME_ExpressionThread,(void*)&Expressions[ExpsNum],0,&dwThreadId);
        dwRet=WaitForMultipleObjects(NumExps,ahThreads,false,dwMilliSeconds); //wait for one of threads to be signaled
        if(dwRet==WAIT_TIMEOUT){
            dwRet=WaitForSingleObject(hSemOnlyOne,0);
            if(dwRet==WAIT_TIMEOUT){
                //one expression is satisfied
                dwRet=WaitForMultipleObjects(NumExps,ahThreads,false,INFINITE);
            }
            else{
                //no expression is satisfied
                dwRet=WAIT_TIMEOUT;
            }
        }
        for(ExpsNum=0;ExpsNum<NumExps;ExpsNum++){
            //stop the rest threads` waiting by add APC to their APC Queues
            if(dwRet==WAIT_TIMEOUT||(dwRet-WAIT_OBJECT_0)!=ExpsNum)
                QueueUserAPC(WFME_ExpressionAPC,ahThreads[ExpsNum],0);
            CloseHandle(ahThreads[ExpsNum]);
        }
    }
    return dwRet;
}
mkelehk 2015-05-14
  • 打赏
  • 举报
回复
引用 4 楼 zgl7903 的回复:
可以用等待时间设置为0 来测试事件有效性,按返回值判定, 多于MAXIMUM_WAIT_OBJECTS 可以分组判定 不过这样系统的开销就比较大些

  HANDLE hEvent[] = {hExit, h1, h2, h3, h4};
  while(1)
  {
    DWORD dwWait = WaitForMultipleObjects(_countof(hEvent), hEvent, FALSE, 0);
    switch(dwWait)
    {
    case(WAIT_FAILED): //错误
      {
        ASSERT(0);
        break;
      }
    case(WAIT_TIMEOUT)://no event signaled 
      {
        break;
      }
    case(WAIT_OBJECT_0 + 0)://thread Exit event
      {
        return 1;
      }
    case(WAIT_OBJECT_0 + 1)://h1
      {
        //add your code
        break;
      }
    case(WAIT_OBJECT_0 + 2)://h2
    case(WAIT_OBJECT_0 + 3)://h3
    case(WAIT_OBJECT_0 + 4)://h4
      {
        //add your code
        break;
      }
    default:
      {
        break;
      }
    }
  }
请问怎样分组判定?
「已注销」 2015-04-22
  • 打赏
  • 举报
回复
其实,同时等待2个事件在实际应用场景中就已经非常罕见了。 所以,微软的64限制,是够用的。 如果需要同时等待很多event,说明程序的设计上存在问题,应修改设计。
zgl7903 2015-04-21
  • 打赏
  • 举报
回复
可以用等待时间设置为0 来测试事件有效性,按返回值判定, 多于MAXIMUM_WAIT_OBJECTS 可以分组判定 不过这样系统的开销就比较大些

  HANDLE hEvent[] = {hExit, h1, h2, h3, h4};
  while(1)
  {
    DWORD dwWait = WaitForMultipleObjects(_countof(hEvent), hEvent, FALSE, 0);
    switch(dwWait)
    {
    case(WAIT_FAILED): //错误
      {
        ASSERT(0);
        break;
      }
    case(WAIT_TIMEOUT)://no event signaled 
      {
        break;
      }
    case(WAIT_OBJECT_0 + 0)://thread Exit event
      {
        return 1;
      }
    case(WAIT_OBJECT_0 + 1)://h1
      {
        //add your code
        break;
      }
    case(WAIT_OBJECT_0 + 2)://h2
    case(WAIT_OBJECT_0 + 3)://h3
    case(WAIT_OBJECT_0 + 4)://h4
      {
        //add your code
        break;
      }
    default:
      {
        break;
      }
    }
  }
mkelehk 2015-04-21
  • 打赏
  • 举报
回复
没人回答,自己顶一下
赵4老师 2015-04-21
  • 打赏
  • 举报
回复
参考人家epoll或boost是怎么做的。
likfeng 2015-04-21
  • 打赏
  • 举报
回复
有其中一个事件等到了就返回,多个事件同时等到时返回最小序号,有什么策略? 感觉没必要用4个线程: 事件多于64时,分组等待 返回值为 WAIT_TIMEOUT 等待下一组 注意最后一个参数不要设置为 INFINITE

15,471

社区成员

发帖
与我相关
我的任务
社区描述
VC/MFC 进程/线程/DLL
社区管理员
  • 进程/线程/DLL社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧