如何使用WaitForMultipleObjects来平衡竞争工作?

Rog*_*and 6 c++ windows winapi multithreading visual-c++

我正在使用WaitForMultipleObjectsIPC的情况,我有一个进程将数据写入两个内存映射文件中的一个或两个,另一个进程在更新时获取该数据.当任一MMF中的数据发生变化时,我正在使用命名事件对象来通知第二个进程.还有一个终止"观察者"线程的事件.

所以代码的简化示例是这样的(编辑 - 注意事件对象已被创建为自动重置事件)

unsigned int CMyClass::ThreadFunc()
{
    // background thread
    HANDLE hEvent[3];

    // open events for updates 0 and 1 and kill signal
    hEvent[0] = ::OpenEvent(SYNCHRONIZE, FALSE, _T("KillEvent"));
    hEvent[1] = ::OpenEvent(SYNCHRONIZE, FALSE, _T("UpdateEvent0"));
    hEvent[2] = ::OpenEvent(SYNCHRONIZE, FALSE, _T("UpdateEvent1"));

    // main loop
    while (true)
    {
        // wait for any event and break on kill signal
        DWORD dwRet = WaitForMultipleObjects(3, hEvent, FALSE, INFINITE);
        if (dwRet == WAIT_OBJECT_0) break;

        // which update event did we get?
        if (dwRet == WAIT_OBJECT_0 + 1) 
        {
            // perform update from channel 0
        }
        else if (dwRet == WAIT_OBJECT_0 + 2)  
        {
            // perform update from channel 1
        }
    }

    // release handles 
    for (int i = 0; i < 3; ++i)
        CloseHandle(hEvent[i]);

    // exit thread
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

在最常见的用例中,只更新了一个MMF,因此该代码工作正常.但是,当两个 MMF都被更新时,我发出两个事件信号,我注意到通过记录和调试,第一个事件的处理频率大约是第二个事件的两倍 - 即使执行更新的进程只是调用SetEvent每个事件它们在相邻的代码行中.这使得一个更新的外观比另一个更慢,因此来自用户的错误报告.

仔细观察MSDN,它表明了为什么会发生这种情况

如果多个对象变为信号,则该函数返回其对象已发出信号的数组中第一个句柄的索引.

所以看起来第二个事件只是打破了等待,如果上面代码中的处理设法在第一个事件上调用另一个之前完成执行SetEvent.

因此,要暂时解决问题,我只是单方面执行两个更新,无论设置了哪个事件.

        // wait for any event
        DWORD dwRet = WaitForMultipleObjects(3, hEvent, FALSE, INFINITE);
        if (dwRet == WAIT_OBJECT_0) break;

        // perform update from channel 0

        // perform update from channel 1
Run Code Online (Sandbox Code Playgroud)

这显然不是理想的,而且非常浪费,因为就像我上面所说的那样,对于最常见的用例,只有一个 MMF正在更新.

处理这种情况的最佳方法是什么?我考虑使用两个线程 - 每个MMF和相应的事件一个 - 但"更新"代码对两者都是通用的,并且将涉及添加当前不必要的大量同步.

我还有其他选择吗?

Sco*_*MVP 5

处理一个事件后,您可以在下一次调用中重新排列传递给 WaitForMultipleObjects 的句柄数组。因此,完成事件 1 会使事件 2 成为下一次的优先事件。反之亦然。