5

MSDNによると:

hEvent : オーバーラップされた I/O 操作が I/O 完了ルーチンなしで発行された場合 (操作の lpCompletionRoutine パラメーターが null に設定されている)、このパラメーターには WSAEVENT オブジェクトへの有効なハンドルが含まれているか、null である必要があります。

私は IOCP を使用しているので、WSASend() または WSARecv() を呼び出すときに、最後のパラメーター (つまり、lpCompletionRoutine) に NULL を渡します。

WSASend(pIoRequest->GetSocket(), pIoRequest->GetWsaBuffer(), 1, NULL, pIoRequest->GetFlags(), pIoRequest, NULL);

WSARecv(pIoRequest->GetSocket(), pIoRequest->GetWsaBuffer(), 1, NULL, &(pIoRequest->GetFlags()), pIoRequest, NULL);

「I/O データごと」のクラス (pIoRequest) は次のようになります。

class IoRequest : public WSAOVERLAPPED
{
public:
    IoRequest()
    {
        ...
        SecureZeroMemory(this, sizeof(WSAOVERLAPPED));
        hEvent = WSACreateEvent(); // A
    }
    ...
    void ResetForNextIoRequest()
    {
        WSACloseEvent(hEvent); // B
        SecureZeroMemory(this, sizeof(WSAOVERLAPPED));
        hEvent = WSACreateEvent(); // C
        ...
    }
    ...
    DWORD& GetFlags() { return m_dwFlags; }
    ...
private:
    ...
    DWORD m_dwFlags;
    ...
};

上記の A、B、C の行をコメントアウトしても、プログラムの動作に違いはないようです。

では、いつ WSACreateEvent() を呼び出すか、単に hEvent を NULL に設定するかをどのように決定すればよいでしょうか?

4

1 に答える 1

18

IOCP を使用している場合は、 GetQueuedCompletionStatus()を使用して完了通知を受け取るため、イベント オブジェクトを渡す必要はありません。これは、 CreateIoCompletionPort()を使用してソケットを完了ポートに関連付けていると仮定して機能します。

はい、Windows の I/O は混乱を招きます。特に、ソケットを使用するには、少なくとも6 つの異なる方法があります。最初にあなたが遭遇したように見える2つ:

  • IOCP を使用したオーバーラップ I/O (CreateIoCompletionPort、GetQueuedCompletionStatus、WSASend など)。これはおそらく最も効率的な方法です。IOCP も使用するあらゆる種類のイベントをイベント ループに簡単に統合できます。その他のイベントについては、 PostQueuedCompletionStatusを使用して回避できる場合があります。これは(AFAIK)多数のソケットに対応する唯一の方法です。

  • IOCP を使用しないオーバーラップ I/O。つまり、イベント オブジェクトで WSASend およびフレンドを使用し、WaitForMultipleObjectsなどを使用してイベントを監視し、 WSAGetOverlappedResultを使用して結果を取得します。これは、HANDLE オブジェクトにもマップできる非ソケット I/O と比較的簡単に統合できます。ただし、WaitForMultipleObjects は、一度に 64 個を超えるハンドルを監視することに制限されています。

また、少なくともさらに 4 つ:

  • 呼び出しのブロック (send、recv、および WSA* バージョン)。これを行うと、スレッドの使用を余儀なくされます。これは、正しく実装するのが難しく、効率が悪い可能性があります。

  • select()を使用したノンブロッキング ソケット。これには、UNIX ライクなシステムと同様のコードを使用できるという利点があります。ただし、(AFAIK)ソケット以外のI / Oと統合することはできません。

  • WSAEventSelectを使用したノンブロッキング。これは、select() メソッドと似ていますが、select() を使用して通知を取得する代わりに、ソケット イベントをイベント オブジェクトにマップし、WaitForMultipleObjectsなどを使用して監視します。これは、IOCP を使用しないオーバーラップ方法にも似ており、64 個以下のオブジェクトという同じ制限に悩まされています。

  • WSAAsyncSelectを使用したノンブロッキング。これは、 Windows メッセージ ループを使用して、ソケット通知をメッセージとしてプログラム内のウィンドウに配信します。これは、多くの GUI アプリケーションなど、既にメッセージ ループを使用しているアプリケーションに簡単に統合できます。

私が何かを忘れた場合、またはこれの一部が実際に機能しない場合は、私を修正してください:)。

于 2012-08-06T15:38:53.740 に答える