IPC の状況で使用WaitForMultipleObjects
しています。1 つのプロセスが 2 つのメモリ マップ ファイルのいずれかまたは両方にデータを書き込み、別のプロセスがそのデータを更新時に取得します。いずれかの MMF のデータが変更されたときに、名前付きイベント オブジェクトを使用して 2 番目のプロセスに通知します。「ウォッチャー」スレッドを終了するためのイベントもあります。
したがって、コードの縮小例は次のようになります (編集 - イベント オブジェクトが自動リセット イベントとして作成されていることに注意してください) 。
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 の 1 つだけが更新されるため、このコードは正常に機能します。ただし、両方のMMF が更新されているため、2 つのイベントが通知されると、ログとデバッグを通じて、最初のイベントが 2 番目のイベントの約 2 倍の頻度で処理されていることに気付きましたSetEvent
。コードの隣接する行でそれらの。これにより、あるアップデートが他のアップデートよりも遅いように見えたため、ユーザーからバグ レポートが寄せられました。
MSDNをよく見ると、なぜこれが起こっているのかがわかります
複数のオブジェクトがシグナル状態になった場合、関数はオブジェクトがシグナル状態になった配列内の最初のハンドルのインデックスを返します。
したがって、最初のイベントで別のイベントが呼び出される前に、上記のコードの処理が実行を終了した場合にのみ、2 番目のイベントが待機を中断しているように見えます。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
これは明らかに理想的ではなく、非常に無駄です。なぜなら、上で述べたように、最も一般的な使用例では、1 つのMMF だけが更新されるからです。
この種の状況を処理する最善の方法は何ですか? 各 MMF と対応するイベントに 1 つずつ、2 つのスレッドを使用することを検討しましたが、「更新」コードは両方に共通であり、現在は不要な多くの同期を追加する必要があります。
他に選択肢はありますか?