3
  hPipe = CreateNamedPipe( 
     lpszPipename,             // pipe name 
     PIPE_ACCESS_DUPLEX,       // read/write access 
     PIPE_TYPE_MESSAGE |       // message type pipe 
     PIPE_READMODE_MESSAGE |   // message-read mode 
     PIPE_WAIT,                // blocking mode 
     PIPE_UNLIMITED_INSTANCES, // max. instances  
     100,                  // output buffer size 
     100,                  // input buffer size 
     0,                        // client time-out 
     NULL);                    // default security attribute 

  DWORD totalBytesAvailable; 
  PeekNamedPipe( 
    hPipe ,                // __in       HANDLE hNamedPipe, 
    NULL,                  // __out_opt  LPVOID lpBuffer, 
    0,                     // __in       DWORD nBufferSize, 
    NULL,                  // __out_opt  LPDWORD lpBytesRead, 
    &totalBytesAvailable,  // __out_opt  LPDWORD lpTotalBytesAvail, 
    NULL                   // __out_opt  LPDWORD lpBytesLeftThisMessage 
  ); 
    if(totalBytesAvailable allows)
    WriteFile( tmp_pipe, pBuffer, BufferLen, &dwWritten, NULL );

ご覧のとおり、以前PeekNamedPipeは使用可能なスペースを確保していましたが、それtotalBytesAvailableは常に0適切であることがわかりました。

4

6 に答える 6

4

私見、実際の書き込みを行う前に空き領域をチェックするこのアプローチには欠陥があります。

実際の書き込みが実行されるまでに、並行して実行されている他のプロセスが空きディスク領域の最後のビットを埋めて、WriteFile が失敗する可能性があります。

私は WriteFile が返すものだけに頼っています。

于 2010-09-15T13:12:23.373 に答える
2

lpTotalBytesAvailパラメーターで返される値は、パイプに書き込まれるのではなく、パイプから読み取ることができるバイト数です。パイプからデータを読み取るバッファを割り当てるための情報を提供します。

パイプ (または任意の NT Krenel ハンドル) への書き込み時にエラーを処理する正しい方法は、単純にWriteFile()の呼び出しを実行し、返されたエラーを処理することです。

チェックしてから書き込むパターンは効果的ではなく、次のようなバグが発生します * テストでは発生しない * フィールドで時々発生する * ... したがって、診断とデバッグが非常に困難です * 最も重要なことに、そのようなバグはユーザーを悩ませます。

その理由は、宛先の状態がチェックと実際の書き込みの間で変化する可能性があるためです。これは、WriteFile() を呼び出すコードでエラーをチェックする必要があることを意味します。これは、WriteFile() を呼び出す前に前提条件をチェックすることは、値を提供しない単なる余分なコードであることを意味します。

このパターンが効果的でない理由は、Windows (および他のすべてのオペレーティング システム - これは Windows だけの問題ではありません) が、"チェック" と "書き込み" をアトミック操作として扱うことができないためです。基盤となる OS は完全に非同期であり、コール間で多くのことが発生する可能性があります。

そのため、単純にWriteFile() を呼び出してエラー処理を適切に行うと、コードはよりシンプルで信頼性が高くなります。

-フォアデッカー

于 2010-09-19T14:22:01.630 に答える
1

PIPE_WAITの代わりにPIPE_NOWAITを設定します。その後、パイプに十分なスペースがない場合、WriteFileはすぐに戻ります。
また、I / Oバッファサイズの場合、100はかなり小さいようです。あなたのパイプは何のためにありますか?

于 2010-09-20T12:18:22.420 に答える
1

あなたがそれをしている方法で空き容量を決定することはできません。

この質問はパイプに関するものですが、利用可能なディスク領域の検出に関する一般的な情報を探している人がいる可能性があります。パイプが最終的にファイルである場合でも、これは役立つ可能性があります。

ナレッジベースの記事「GetDiskFreeSpaceとGetDiskFreeSpaceExの理解と使用」では、空きディスク容量を決定するための関連するWin32 APIに関する情報を提供するか、次のAPIドキュメントに直接アクセスしてください。

于 2010-09-14T07:13:04.537 に答える
1

チェックしてから書き込むことの脆弱性に関するコメントは正しいです。

PIPE_NOWAIT の提案は、Microsoft によって推奨されていません。

重複した I/O を使用します。その後、WriteFile() は常にすぐに戻り、データがパイプにすぐに書き込まれなかった場合は ERROR_IO_PENDING で FALSE を返します。その場合、CancelIo() を呼び出して、試行された WriteFile() をキャンセルします。CancelIo() を呼び出した後、GetOverlappedResult() を呼び出す必要があることに注意してください。オーバーラップした WriteFile() はまだ完了する必要があるためです。失敗する可能性があり、その前に OVERLAPPED 構造を解放すると、スタックが破損します。

ところで、この質問に対する回答を受け入れる必要があります。お願いしてから1年以上!

于 2011-10-10T15:48:48.873 に答える
0

クライアントがパイプを空にするのを待って、ライターがハングする問題がないように、パイプへの書き込みを処理するスレッドを作成しますか?

于 2010-09-21T01:56:43.167 に答える