3

I/O 保留中の要求をキューから取り出し、処理し、割り当てを解除する従来の IOCP コールバックがあります。

struct MyIoRequest { OVERLAPPED o; /* ... other params ... */ };
bool is_iocp_active = true;

DWORD WINAPI WorkerProc(LPVOID lpParam)
{
    ULONG_PTR dwKey;
    DWORD dwTrans;
    LPOVERLAPPED io_req;
    while(is_iocp_active)
    {
        GetQueuedCompletionStatus((HANDLE)lpParam, &dwTrans, &dwKey, (LPOVERLAPPED*)&io_req, WSA_INFINITE); 
       // NOTE, i could use GetQueuedCompletionStatusEx() here ^ and set it in the 
       // alertable state TRUE, so i can wake up the thread with an ACP request from another thread!

        printf("dequeued an i/o request\n");
        // [ process i/o request ]
        ...

        // [ destroy request ]
        destroy_request(io_req);
    }
    // [ clean up some stuff ] 
    return 0;
}

次に、コードのどこかに次のように記述します。

MyIoRequest * io_req = allocate_request(...params...);
ReadFile(..., (OVERLAPPED*)io_req);

これは完璧に機能します。

ここで私の質問は次のとおりです。リークを引き起こさずに IOCP キューをすぐに閉じたいのですが? (例: アプリケーションは終了する必要があります) つまり: is_iocp_active を「false」に設定すると、次回 GetQueuedCompletionStatus() が新しい i/o 要求をデキューし、それが最後の i/o 要求になります: それが返され、スレッドがMSDN によると、スレッドが終了すると、保留中のすべての i/o 要求がシステムによってキャンセルされるだけです。

しかし、ReadFile() を呼び出すときにインスタンス化した「MyIoRequest」タイプの構造はまったく破棄されません。システムは保留中の I/O 要求をキャンセルしましたが、作成した構造を手動で破棄する必要があります。ループを停止すると、保留中のすべての I/O 要求がリークします。

それで、どうすればこれを行うことができますか?その変数をfalseに設定するだけでIOCPループを停止するのは間違っていますか? APCリクエストを使用してアラート可能なスレッドを停止した場合でも発生することに注意してください。

私の頭に浮かぶ解決策は、すべての「MyIoRequest」構造をキュー/リストに追加し、GetQueuedCompletionStatusEx が返されたときにそれらをデキューすることですが、そのような MyIoRequest 構造のエンキュー/デキュープロセスは連動?IOCP ループの使い方を誤解しているのかもしれません。誰かがこのトピックに光を当てることができますか?

4

2 に答える 2

4

私が通常 IOCP スレッドをシャットダウンする方法は、自分自身の「今すぐシャットダウンしてください」完了を投稿することです。そうすれば、保留中のすべての完了をきれいにシャットダウンして処理してから、スレッドをシャットダウンできます。

これを行う方法は、num バイト、完了キー、および pOverlapped に 0 を指定して PostQueuedCompletionStatus() を呼び出すことです。これは、完了キーが一意の値であることを意味します (ハンドル/完了キーがゼロの有効なファイルまたはソケットはありません)。

ステップ 1 は、完了のソースを閉じることです。そのため、ソケット接続を閉じるか中止し、ファイルを閉じます。これらがすべて閉じられると、それ以上完了パケットを生成できなくなるため、特別な '0' 完了を投稿します。IOCP にサービスを提供しているスレッドごとに 1 つ投稿してください。スレッドが「0」完了キーを取得すると、スレッドは終了します。

于 2013-03-22T08:37:06.650 に答える
-1

アプリを終了する予定であり、終了しない理由がない場合(たとえば、DB接続を閉じる、プロセス間共有メモリの問題)、ExitProcess(0)を呼び出します。

それができない場合は、すべてのソケットハンドルに対してCancelIO()を呼び出し、キャンセルされたすべての完了を処理します。

最初にExitProcess()を試してください!

于 2013-03-21T12:55:46.440 に答える