0

フレームワークで一般的なスレッド割り込みメカニズムとしてユーザー アラートを使用するため、fAlertable を TRUE に設定してこの関数を使用しています。この関数に関する MSDN ページのコメントによると、

呼び出しがアラート可能な待機状態に入り、ユーザー APC が GetQueuedCompletionStatusEx の戻り値を TRUE にディスパッチできる場合、ulEntriesRemoved はゼロではなく、OVERLAPPED_ENTRY の「パック」は変更されません。したがって、API を呼び出す前に、すべての OVERLAPPED_ENTRY の lpOverlapped メンバーに既知の一意の値が設定されていることを確認すると、削除されたエントリが APC であるか I/O 完了パケットであるかをより簡単に検出できます。価値。

最初のエントリだけでなく、すべての OVERLAPPED_ENTRY をチェックする必要があるのはなぜですか? GetQueuedCompletionStatusEx() は常に出力配列を順番に埋めるのではないので、配列全体 (または少なくとも ulEntriesRemoved まで) をループするのではなく、最初のものだけをチェックする必要がありますか? さらに、この関数が複数の完了ポート エントリを同時にデキューすることを考えると、アラートと 1 つ以上の完了エントリの両方を決して返さないことが保証されますか? アラート中に ulEntriesRemoved がゼロ以外になるというコメントのメモを考えると、この可能性について特に心配しています。このページのコメントには、「キューに I/O 完了パケットがある場合、ユーザー APC はディスパッチされません」と記載されていますが、

システムが、スレッドに対するユーザー アラートと完了ポート エントリの両方を組み合わせてキューに入れ、スレッドが GetQueuedCompletionStatusEx() を実行するとします。ドキュメントから、関数がこの呼び出しですべての完了エントリをデキューし、その後の各呼び出しごとに 1 つのユーザー アラートをデキューするかどうかはわかりません (これ以上完了エントリがキューに入れられていないと仮定します)。ドキュメントを考えると、それが最も可能性の高いケースのように思われますが、間違っていると判明する可能性のある仮定をしたくありません...

4

1 に答える 1

2

私の知る限り、ユーザーAPCが実行されたときにGetQueuedCompletionStatusEx戻ります。FALSEそしてGetLastError()戻るWAIT_IO_COMPLETION。したがって、ユーザー APC が実行されたときに完了パケットをデキューすることはありません。

これは私にとって完璧に機能する私のコードです。

if (!::GetQueuedCompletionStatusEx(m_hIoCompletionPort, CompletionPackets, uCompletionPacketsToDequeue, &uCompletionPacketsRemoved, dwTimeToSleep, TRUE))
{
    DWORD dwError = ::GetLastError();

    if (dwError == WAIT_IO_COMPLETION)
    {
        // User Terminate Instance.
        ATLASSERT(m_blTerminating);
        hrResult = S_OK;
        break;
    }
    else if (dwError != ERROR_TIMEOUT)
    {
        hrResult = HRESULT_FROM_WIN32(dwError);
        break;
    }

    // One or more Timer has elapsed.
    ATLASSERT(m_Timers.GetCount() != 0);
    uCompletionPacketsRemoved = 0;
}
于 2013-09-10T02:41:21.863 に答える