web-dev-qa-db-ja.com

ReadFile()ブロッキングの解除-名前付きパイプ(Windows API)

簡単にするために、これはNamedPipe SERVERがNamedPipe CLIENTがパイプに書き込むのを待っている状況です(WriteFile()を使用)

ブロックしているWindowsAPIはReadFile()です

サーバーは、ブロッキングが有効になっている同期パイプ(オーバーラップI/Oなし)を作成しました

クライアントが接続し、サーバーはデータを待機しています。

通常のフローでは、クライアントはデータを送信し、サーバーはそれを処理してから、ReadFile()に戻って次のデータチャンクを待ちます。

その間にイベントが発生し(ユーザー入力など)、NamedPipe SERVERは他のコードを実行する必要がありますが、ReadFile()がブロックしている間は実行できません。

この時点で、NamedPipeクライアントは私のアプリケーションではないため、制御できません。サーバーのブロックを解除するために数バイトを送信させることはできません。そこに座ってデータを送信しないだけです。クライアントの実装を制御できないため、そのために何も変更することはできません。

1つの解決策は、すべてのReadFile()操作が実行される別のスレッドを作成することです。そうすれば、イベントが発生したときに、コードを処理するだけで済みます。これに伴う問題は、イベントにも個別のスレッドが必要なため、このサーバーのインスタンスごとに2つの追加スレッドがあることです。これはスケーラブルである必要があるため、これは望ましくありません。

別のスレッドから私は呼び出してみました

 DisconnectNamedPipe()

そして

 CloseHandle()

それらは両方とも戻りません(クライアントがパイプに書き込むまで)。

同じパイプに接続して数バイトを書き込むことができない理由は次のとおりです。

「名前付きパイプのすべてのインスタンスは同じパイプ名を共有しますが、各インスタンスには独自のバッファーとハンドルがあり、クライアント/サーバー通信用の個別のコンジットを提供します。」

http://msdn.Microsoft.com/en-us/library/aa365590.aspx

私はそれを偽造する方法が必要なので、64,000ドルの質問は次のとおりです。

ReadFile()のブロックを解除するにはどうすればよいですか?

23
Mike Trader

ReadFileの前にこれを試してください:

BOOL WINAPI PeekNamedPipe(
  __in       HANDLE hNamedPipe,
  __out_opt  LPVOID lpBuffer,
  __in       DWORD nBufferSize,
  __out_opt  LPDWORD lpBytesRead,
  __out_opt  LPDWORD lpTotalBytesAvail,
  __out_opt  LPDWORD lpBytesLeftThisMessage
);

if(TotalBytesAvail > 0)
  ReadFile(....);

-AV-

16
Artkov

CancelSynchronousIoをご覧ください

指定されたスレッドによって発行された保留中の同期I/O操作をキャンセル済みとしてマークします。

そしてCancelIo/CancelIoEx:

保留中のすべての非同期I/O操作をキャンセルするには、次のいずれかを使用します。

CancelIo —この関数は、指定されたファイルハンドルに対して呼び出しスレッドによって発行された操作のみをキャンセルします。

CancelIoEx —この関数は、指定されたファイルハンドルに対してスレッドによって発行されたすべての操作をキャンセルします。

6
alex2k8

マイク、

同期ReadFileをキャンセルすることはできません。ただし、非同期(重複)操作に切り替えることができます。これを行うことで、かなりスケーラブルなアーキテクチャを実装できます。

可能なアルゴリズム(単なるアイデア):

  • 新しいクライアントごとにReadFileを呼び出します
  • ハンドルがオーバーラップしているWaitForMultipleObjects.hEvent +カスタムイベント
  • シグナルされたイベントを反復処理し、スレッドプールからのスレッドによる実行のためにそれらをスケジュールします。

このように、実際のデータ処理はスレッドプールによって実行できますが、接続を受信して​​データを読み取るためのスレッドはわずかです。

3
alex2k8

これに伴う問題は、イベントにも個別のスレッドが必要なため、このサーバーのインスタンスごとに2つの追加スレッドがあることです。これはスケーラブルである必要があるため、これは望ましくありません。

私のキャリアの中で、「スレッドが多い」==「スケーラブルでない」ことに気付いたことはありません。これらの「サーバー」インスタンスはいくつありますか?

通常、操作がブロックされる場合、操作は別のスレッドで実行する必要があり、操作がブロックされている間、システムは応答する必要があります。

2
Kevin

何が起こっているのかというと、クライアントがサーバーのインバウンドパイプ(もう存在しない)に接続しようとしている間、サーバーのアウトバウンドパイプは接続を待機して開いたままになります...ループするためにアウトバウンドパイプをフラッシュする必要がありますインバウンドに戻ります。ファイルを読み取ることにより、クライアント側でフラッシュすることができます(そこには「ハンドシェイク」があり、最初は機能しないため、接続確立をループすることを忘れないでください)

1
user3498796

非同期I/O操作は、I/O完了ポートを使用する場合、スレッドをブロックする必要はありません。参照: http://msdn.Microsoft.com/en-us/library/aa365198(VS.85).aspx

1
Emil