8

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 つのスレッドを使用することを検討しましたが、「更新」コードは両方に共通であり、現在は不要な多くの同期を追加する必要があります。

他に選択肢はありますか?

4

2 に答える 2

5

1 つのイベントを処理した後、次の呼び出しで WaitForMultipleObjects に渡されるハンドルの配列を再配置できます。したがって、イベント 1 を完了すると、次回はイベント 2 が優先イベントになります。およびその逆。

于 2013-05-30T13:45:36.440 に答える
3

からの戻り値WaitForMultipleObjectsWAIT_OBJECT_1の場合でも、MMF 2 のイベントがWaitForSingleObjectを使用して設定されているかどうかを確認できます。

DWORD dwRet = WaitForMultipleObjects(3, hEvent, FALSE, INFINITE);

if (dwRet == WAIT_OBJECT_0) break;

// decide which MMFs need processing
if ( dwRet == WAIT_OBJECT_1 )
{
    if ( WaitForSingleObject( hEvent[2], 0 ) == WAIT_OBJECT_0 )
        // both MMFs have been updated, decide which to do first.
    else
        // only MMF 1 has been updated, process that
}
else if ( dwRet == WAIT_OBJECT_2 )
{
    // only MMF 2 has been updated as WaitForMultipleObjects returns 
    // lowest index of set event.
}

// do processing
于 2013-05-30T07:43:59.480 に答える