同期パイプ I/O と重複パイプ I/O

ReadFileWriteFileTransactNamedPipeおよび ConnectNamedPipe 関数は、パイプに対して同期的または非同期的に入出力操作を実行できます。 関数が同期的に実行されると、実行している操作が完了するまで戻りません。 つまり、呼び出し元のスレッドの実行は、時間のかかる操作の完了を待機している間、無期限にブロックされる可能性があります。 関数が非同期的に実行されると、操作が完了していない場合でも、すぐにが返されます。 これにより、呼び出し元のスレッドが他のタスクを自由に実行できる間に、時間のかかる操作をバックグラウンドで実行できます。

非同期 I/O を使用すると、パイプ サーバーは次の手順を実行するループを使用できます。

  1. wait 関数の呼び出しで複数のイベント オブジェクトを指定し、いずれかのオブジェクトがシグナル状態に設定されるのを待ちます。
  2. 待機関数の戻り値を使用して、どの重複する操作が完了したかを確認します。
  3. 完了した操作をクリーンし、そのパイプ ハンドルの次の操作を開始するために必要なタスクを実行します。 これには、同じパイプ ハンドルに対して別の重複する操作を開始する必要があります。

重複する操作により、1 つのパイプで同時にデータの読み取りと書き込みを行い、1 つのスレッドで複数のパイプ ハンドルに対して同時 I/O 操作を実行できます。 これにより、シングルスレッド パイプ サーバーは、複数のパイプ クライアントとの通信を効率的に処理できます。 例については、「重複した I/O を使用する名前付きパイプ サーバー」を参照してください。

パイプ サーバーが同期操作を使用して複数のクライアントと通信するには、パイプ クライアントごとに個別のスレッドを作成して、他のスレッドが待機している間に 1 つ以上のスレッドを実行できるようにする必要があります。 同期操作を使用するマルチスレッド パイプ サーバーの例については、「 マルチスレッド パイプ サーバー」を参照してください。

非同期操作の有効化

ReadFileWriteFileTransactNamedPipeおよび ConnectNamedPipe 関数は、指定されたパイプ ハンドルに対して重複モードを有効にし、OVERLAPPED 構造体への有効なポインターを指定した場合にのみ、非同期的に実行できます。 OVERLAPPED ポインターが NULL の場合、関数の戻り値は操作が完了したことを誤って示している可能性があります。 そのため、FILE_FLAG_OVERLAPPEDを使用してハンドルを作成し、非同期動作が必要な場合は、常に有効な OVERLAPPED 構造体を指定することを強くお勧めします。

指定した OVERLAPPED 構造体の hEvent メンバーには、手動リセット イベント オブジェクトへのハンドルが含まれている必要があります。 これは、 CreateEvent 関数によって作成された同期オブジェクトです。 重複する操作を開始するスレッドは、イベント オブジェクトを使用して、操作がいつ終了したかを判断します。 同じハンドルに対して同時操作を実行するときに、パイプ ハンドルを同期に使用しないでください。これは、どの操作の完了によってパイプ ハンドルが通知されたのかを知る方法がないためです。 同じパイプ ハンドルに対して同時操作を実行するための唯一の信頼性の高い手法は、操作ごとに独自のイベント オブジェクトを持つ個別の OVERLAPPED 構造体を使用することです。 イベント オブジェクトの詳細については、「 同期」を参照してください。

また、重複した操作が完了したときに、GetQueuedCompletionStatus 関数または GetQueuedCompletionStatusEx 関数を使用して通知を受け取ることができます。 この場合、 OVERLAPPED 構造体で手動リセット イベントを割り当てる必要はありません。また、完了は、非同期の読み取りまたは書き込み操作と同じ方法でパイプ ハンドルに対して行われます。 詳細については、「 I/O 完了ポート」を参照してください。

ReadFileWriteFileTransactNamedPipeConnectNamedPipe の各操作が非同期的に実行されると、次のいずれかが発生します。

  • 関数が戻るときに操作が完了した場合、戻り値は操作の成功または失敗を示します。 エラーが発生した場合、戻り値は 0 で、 GetLastError 関数はERROR_IO_PENDING以外のものを返します。
  • 関数が戻るときに操作が完了していない場合、戻り値は 0 で 、GetLastError はERROR_IO_PENDINGを返します。 この場合、呼び出し元のスレッドは操作が完了するまで待機する必要があります。 呼び出し元のスレッドは 、GetOverlappedResult 関数を呼び出して結果を確認する必要があります。

完了ルーチンの使用

ReadFileEx 関数と WriteFileEx 関数は、重複する別の形式の I/O を提供します。 イベント オブジェクトを使用して完了を通知する重複する ReadFile 関数と WriteFile 関数とは異なり、拡張関数は 完了ルーチンを指定します。 完了ルーチンは、読み取り操作または書き込み操作が完了したときに実行キューに入る関数です。 完了ルーチンは、ReadFileExWriteFileEx を呼び出したスレッドが、fAlertable パラメーターを TRUE に設定してアラート可能な待機関数のいずれかを呼び出して、警告可能な待機操作を開始するまで実行されません。 警告可能な待機操作では、 ReadFileEx または WriteFileEx 完了ルーチンが実行のためにキューに入っている場合にも、関数は を返します。 パイプ サーバーは、拡張関数を使用して、接続するクライアントごとに一連の読み取り操作と書き込み操作を実行できます。 シーケンス内の各読み取り操作または書き込み操作は完了ルーチンを指定し、各完了ルーチンはシーケンス内の次のステップを開始します。 例については、「 完了ルーチンを使用した名前付きパイプ サーバー」を参照してください。