8

このCreateIoCompletionPort関数を使用すると、新しい I/O 完了ポートを作成し、既存の I/O 完了ポートにファイル ハンドルを登録できます。

recv次に、ソケットに対する や構造をReadFile持つファイルに対するなど、任意の関数を使用OVERLAPPEDして非同期操作を開始できます。

関数呼び出しがOVERLAPPED構造体で呼び出されたにもかかわらず同期的に返されたかどうかを確認する必要があり、この場合は直接処理します。それ以外の場合は、ERROR_IO_PENDINGが返さGetQueuedCompletionStatusれたときに、操作が完了したときに通知される機能を使用できます。

発生する質問は次のとおりです。

  • I/O 完了ポートからハンドルを削除するにはどうすればよいですか? たとえば、ソケットを IOCP に追加する場合、閉じているソケットを削除するにはどうすればよいですか? 同じ完了キーで別のソケットを再登録する必要がありますか?

  • また、呼び出しが常に I/O 完了ポートを通過し、同期的に返されないようにする方法はありますか?

  • そして最後に、たとえばrecv非同期ではなくsend同期にすることは可能ですか? たとえば、単純なエコー サービスが実装されている場合:コードの複雑さを軽減するために、recv新しいデータを非同期で待機し、応答を同期的に待機することはできますか? send私の場合、recv最初のリクエストが処理される前に、とにかく二度目はしません。

  • 非同期ReadFileが要求されたが、それが完了する前にWriteFile、同じファイルへの を処理する必要がある場合はどうなりますか。ReadFileエラーメッセージが表示されてキャンセルされ、書き込みが完了したらすぐに読み取りプロセスを再開する必要がありますか? ReadFileまたは、書き込む前に手動でキャンセルする必要がありますか? この問題は、通信デバイスと組み合わせて発生します。そのため、書き込みと読み取りが同時に発生しても問題は発生しません。

4

4 に答える 4

11

I/O 完了ポートからハンドルを削除するにはどうすればよいですか?

私の経験では、完了ポートからハンドルの関連付けを解除することはできません。OVERLAPPEDただし、構造体のhEventフィールドの下位ビットを設定することで、完了ポート通知を無効にすることができます。 GetQueuedCompletionStatusのドキュメントを参照してください。

たとえば、ソケットを IOCP に追加する場合、閉じているソケットを削除するにはどうすればよいですか? 同じ完了キーで別のソケットを再登録する必要がありますか?

I/O 完了ポートからハンドルの関連付けを明示的に解除する必要はありません。ハンドルを閉じるだけで十分です。複数のハンドルを同じ完了キーに関連付けることができます。どの要求が I/O 完了に関連付けられているかを判断する最善の方法は、OVERLAPPED構造体を使用することです。実際、追加のデータを格納するために拡張OVERLAPPEDすることさえできます。

また、呼び出しが常に I/O 完了ポートを通過し、同期的に返されないようにする方法はありますか?

ReadFile/が をWriteFile返す場合でも、これがデフォルトの動作ですTRUESetFileCompletionNotificationModesを明示的に呼び出して、TRUEおよびERROR_SUCCESSが返されたときに完了パケットをキューに入れないように Windows に指示する必要があります。

たとえば、recv非同期にsend同期することは可能ですか?

recvandを使用しないでくださいsend。、、または代わりに andOVERLAPPEDなどの構造を受け入れる関数を使用する必要があります。コードが、ソケットと名前付きパイプの両方など、複数のタイプの I/O ハンドルを処理することを意図している場合は、後者を使用する方が便利な場合があります。これらの関数は同期モードを提供するため、それらを使用すると、非同期呼び出しと同期呼び出しを混在させることができます。WSARecvWSASendReadFileWriteFile

非同期の ReadFile が要求されたが、それが完了する前に、同じファイルへの WriteFile を処理する必要がある場合はどうなりますか?

暗黙のキャンセルはありません。全二重デバイスへの読み取り/書き込みごとに個別の構造を使用している限り、OVERLAPPED同時 I/O 操作を実行できない理由はわかりません。

于 2011-07-04T15:21:22.080 に答える
3

最初にいくつかの重要な修正。

重複した I/O 操作がすぐに完了する (ReadFileまたは同様の I/O 関数が成功を返す) 場合、I/O の完了は既にIOCP にスケジュールされています。

また、あなたの質問によると、ファイル/ソケットハンドルと、それらに対して発行された特定の I/O 操作を混同していると思います。

さて、あなたの質問に関して:

  1. 私の知る限り、IOCP からファイル/ソケット ハンドルを削除する従来の方法はありません (通常、これを行う必要はありません)。閉じたハンドルを IOCP から削除することについて話していますが、これはまったく正しくありません。有効なカーネル オブジェクトを参照していないため、閉じたハンドルを削除することはできません。

より正しい質問は、ファイル/ソケットを適切に閉じる方法です。答えは、ハンドルを閉じるだけです。すべての未解決の I/O 操作 (このハンドルで発行された) は、すぐにエラー コード (中止) で返されます。次に、完了ルーチン (GetQueuedCompletionStatusループで呼び出すルーチン) で、I/O ごとに必要なクリーンアップを実行する必要があります。

  1. 既に述べたように、すべての I/O 完了は、同期と非同期の両方のケースで IOCP に到達します。IOCP に到達しない唯一の状況は、I/O がエラーで同期的に完了する場合です。とにかく、統一された処理が必要な場合 - そのような場合、人工的な完了データを IOCP に投稿できます (使用PostQueuedCompletionStatus)。

  2. オーバーラップ I/O にはWSASendand WSARecv( recvandではなく) を使用する必要があります。sendそれにもかかわらず、ソケットがフラグ付きで開かれた場合でも、構造体を指定せずに I/O 関数を呼び出すWSA_FLAG_OVERLAPPEDことができます。OVERLAPPEDこのような場合、これらの関数は同期して動作します。すべての関数呼び出しに対して同期/非同期モードを決定できるようにします。

  3. 重複した読み取り/書き込み要求を混在させても問題はありません。ここでの唯一のデリケートな点は、現在書き込み中のファイル位置からデータを読み取ろうとするとどうなるかです。結果は、ハードウェアによる I/O の完了順序、一部の PC タイミング パラメータなどの微妙な事柄に依存する場合があります。このような状況は避ける必要があります。

于 2011-07-04T15:31:49.683 に答える
0

I/O 完了ポートからハンドルを削除するにはどうすればよいですか? たとえば、ソケットを IOCP に追加する場合、閉じているソケットを削除するにはどうすればよいですか? 同じ完了キーで別のソケットを再登録する必要がありますか?

あなたはそれを間違った方法で手に入れました。ファイル オブジェクトが使用する I/O 完了ポートを設定します。ファイル オブジェクトが削除されても、心配する必要はありません。あなたが混乱している理由は、Win32 が基礎となるネイティブ API 機能を公開する方法のためです ( CreateIoCompletionPort1 つの関数で 2 つの非常に異なることを行います)。

また、呼び出しが常に I/O 完了ポートを通過し、同期的に返されないようにする方法はありますか?

これがいつものやり方です。完了通知の処理方法をカスタマイズできるのは、Windows Vista 以降だけです。

非同期の ReadFile が要求されたが、それが完了する前に、同じファイルへの WriteFile を処理する必要がある場合はどうなりますか。エラー メッセージが表示されて ReadFile がキャンセルされ、書き込みが完了したらすぐに読み取りプロセスを再開する必要がありますか?

Windows での I/O 操作は本質的に非同期であり、要求は常にキューに入れられます。非同期 I/O を有効にするFILE_FLAG_OVERLAPPEDには inを指定する必要があるため、そうではないと思うかもしれません。CreateFileただし、ネイティブ層では、同期 I/O は実際にはアドオンであり、カーネルがファイルの位置を追跡し、I/O が完了するのを待ってから戻る便利なものです。

于 2011-07-05T13:28:31.760 に答える