9

IO 完了ルーチンを使用して、パイプを介して異なるマシン上の 2 つのプロセス間で通信しています。

WriteFileEx の完了ルーチンが呼び出されると、完了ルーチンのパラメーター dwErrorCode が 0 (つまり、エラーなし) で、GetOverlappedResult が true (つまり、エラーなし) を返しますが、dwNumberOfBytesTransfered が WriteFileEx の呼び出しの nNumberOfBytesToWrite と一致しないことがあります。ただし、これはパイプのクライアント側でのみ表示されます。

転送されたバイト数が、転送を要求されたバイト数と一致しない場合、どのようにしてこれが成功したと見なすことができますか?

これは、パイプへのクライアントのハンドルが作成される方法です。

mHPipe = CreateFile(pipeName,                 // pipe name 
                    GENERIC_READ |            // read and write access 
                    GENERIC_WRITE, 
                    0,                        // no sharing 
                    NULL,                     // default security attributes
                    OPEN_EXISTING,            // opens existing pipe 
                    FILE_FLAG_OVERLAPPED |    // overlapped
                    FILE_FLAG_WRITE_THROUGH,  // write through mode
                    NULL);                    // no template file 

// do some checking...

// The pipe connected; change to message-read mode. 
DWORD dwMode = PIPE_READMODE_MESSAGE; 
BOOL fSuccess = SetNamedPipeHandleState(mHPipe,   // pipe handle 
                                        &dwMode,  // new pipe mode 
                                        NULL,     // don't set maximum bytes 
                                        NULL);    // don't set maximum time 

なぜこれが起こるのか誰にもわかりますか?

ありがとう

編集:

関連する WriteFileEx コードは次のとおりです。

void WINAPI CompletedWriteRoutine(DWORD dwErrorCode, DWORD dwNumberOfBytesTransfered, LPOVERLAPPED lpOverLap)
{
  BOOL fWrite = FALSE;
  LPPIPEINST lpPipeInst = (LPPIPEINST)lpOverLap;

  //
  // !  99.9% of the time, dwNumberOfBytesTransfered == lpPipeInst->cbDataSize
  //    but 0.1% of the time, they do not match
  //

  // Some stuff

  // Copy next message to send
  memcpy_s(lpPipeInst->chData, sizeof(lpPipeInst->chData), pMsg->msg, pMsg->size);
  lpPipeInst->cbDataSize = pMsg->size;

  // Some other stuff

  fWrite = WriteFileEx(lpPipeInst->hPipeInst,
                       lpPipeInst->chData,
                       lpPipeInst->cbDataSize,
                       (LPOVERLAPPED) lpPipeInst,
                       (LPOVERLAPPED_COMPLETION_ROUTINE)CompletedWriteRoutine);

  // Some other, other stuff
}

LPPIPEINST は次のように宣言されます。

typedef struct 
{ 
  OVERLAPPED oOverlap;      // must remain first item
  HANDLE hPipeInst;
  TCHAR chData[BUFSIZE];
  DWORD cbDataSize;
} PIPEINST, *LPPIPEINST;

そして、CompletedWriteRoutine への最初の呼び出しには、次のように宣言された lpOverlap パラメーターが与えられます。

PIPEINST pipeInstWrite        = {0};
pipeInstWrite.hPipeInst       = client.getPipeHandle();
pipeInstWrite.oOverlap.hEvent = hEvent[eventWriteComplete];

編集:

ハリーが提案したように重複した構造を再初期化しようとした後、私は奇妙なことに気付きました. memset各の前にOVERLAPPED構造体をゼロにしWriteFileEx、約 1/5000 の完了ルーチン コールバックで、cbWrittenパラメーターとOVERLAPPED構造体のInternalHighメンバーが、最新のメッセージではなく、前のメッセージのサイズに設定されました。完了ルーチン内のパイプのクライアント側とサーバー側の両方でファイルにログを追加したところ、両端で送受信されたデータは完全に一致しました (そして正しい期待データ)。これにより、データをファイルに書き込むのにかかる時間InternalHighで、構造内のメンバーOVERLAPPEDが変更され、予想していたメッセージのサイズが反映されたことが明らかになりました (cbWritten古いメッセージ サイズのままです)。ファイルのログを削除したところ、次のコードで時計仕掛けのような問題を再現できるようになりました。

void WINAPI CompletedWriteRoutine(DWORD dwErr, DWORD cbWritten, LPOVERLAPPED lpOverLap)
{
  LPPIPEINST lpPipeInst = (LPPIPEINST)lpOverLap;

  // Completion routine says it wrote the amount of data from the previous callback
  if (cbWritten != lpPipeInst->cbDataSize)
  {
    // Roughly 1 in 5000 callbacks ends up in here

    OVERLAPPED ovl1 = lpPipeInst->oOverlap; // Contains size of previous message, i.e. cbWritten
    Sleep(100);
    OVERLAPPED ovl2 = lpPipeInst->oOverlap; // Contains size of most recent message, i.e lpPipeInst->cbDataSize
  }
  ...
}

構造体の前に完了ルーチンが呼び出されOVERLAPPED、完了ルーチンの入力パラメーターが更新される場合があるようです。MsgWaitForMultipleObjectsEx(eventLast, hEvent, INFINITE, QS_POSTMESSAGE, MWMO_ALERTABLE);Windows 7 64ビットで呼び出される完了ルーチンに使用しています。

このMSDNページには次のように書かれています:

「完了ルーチンが呼び出された後、システムは OVERLAPPED 構造を使用しないため、完了ルーチンはオーバーラップされた構造によって使用されているメモリの割り当てを解除できます。」

...どうやら、このコードが再現できることは決して起こらないはずですか?

これは WINAPI のバグですか?

4

1 に答える 1

3

通話FILE_FLAG_NO_BUFFERINGに追加- それ以来、問題は発生していません。CreateFileお時間を割いてコメントしてくださった皆様、ありがとうございました。

于 2012-12-03T08:25:20.707 に答える