【发布时间】:2013-05-25 16:16:06
【问题描述】:
我在 IPC 情况下使用WaitForMultipleObjects,其中我有一个进程将数据写入两个内存映射文件中的一个或两个,而另一个进程在数据更新时获取该数据。当任一 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;
}
在最常见的用例中,仅更新了一个 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
这显然不理想而且非常浪费,因为就像我上面所说的,对于最常见的用例,只有 一个 MMF 正在更新。
处理这种情况的最佳方法是什么?我考虑过使用两个线程——一个用于每个 MMF 和相应的事件——但是“更新”代码对两者都是通用的,并且会涉及添加许多当前不必要的同步。
我还有其他选择吗?
【问题讨论】:
标签: c++ windows multithreading winapi visual-c++