2

HasOverlappedIoCompleted()ReadFileEx()およびで開始された非同期I/Oでは機能しませんWriteFileEx()。下部のコードスニペットはこれを示しています。この例でReadFileEx()は、入力のないパイプから読み取るため、読み取りは完了しません。ただし、HasOverlappedIoCompleted()TRUEを返します。呼び出しをオーバーラップに変更すると、ReadFile()期待HasOverlappedIoCompleted()どおりにFALSEが返されます。

私の質問は、コールバック自体に依存せずに、コールバックと重複したI / O要求が完了したかどうかを確認するにはどうすればよいですか?私のアプリケーションでは、APCはキューに入れられている可能性がありますが、アプリケーションがアラート可能な状態でまだ待機していない可能性があるため、必ずしも実行されている必要はありません。

ありがとう。

(GetOverlappedResult()は役に立ちません-TRUEも返します。)

もう少し背景:ReadFileEx()問題を簡単に示すことができるため、私が使用している例では。私のアプリケーションではWriteFileEx()、パイプインスタンスを繰り返し呼び出しています。前のメッセージWriteFileEx()がまだ完了していない場合は、メッセージを送信するのではなくドロップする必要があります(同じパイプインスタンスに複数の保留中の書き込みがないようにする必要があります)が、前のメッセージがWriteFileEx() 完了している場合は、次のメッセージを開始する必要があります。完了コールバックはまだ実行されていません

編集:問題のシナリオの説明

  1. スレッドはアラート可能状態になります(1つの読み取りAPCがキューに入れられます)。
  2. 読み取りAPCが開始されます。WriteFileEx()をキューに入れ、「書き込み保留」フラグを設定します。次に、ReadFileEx()をキューに入れます。
  3. メインスレッドが作業を開始します(アラート不可)。
  4. キューに入れられた読み取りが完了します。
  5. キューに入れられた書き込みが完了します(読み取り後)。
  6. メインスレッドはアラート状態になります。
  7. 読み取りAPCはキューの最初にあるため、最初に実行されます。「書き込み保留中」フラグを調べ、まだ設定されているため、書き込みをドロップします。実際、WriteFileEx()完了しましたが、ReadFileEx()が最初に完了したため、まだAPCを呼び出していません。

カスタムの「書き込み保留」フラグをテストする代わりに、APCがまだ実行されていない場合でも、WriteFileEx()が実際に完了したかどうかをOSから確認したいと思います。


#include <Windows.h>
#include <stdio.h>
#include <assert.h>

VOID CALLBACK readComplete(DWORD err, DWORD bytes, LPOVERLAPPED ovlp)
{
}

int main(int argc, char *argv[])
{
  HANDLE     hServer;
  OVERLAPPED serverOvlp = { 0 };
  HANDLE     hClient;
  DWORD      bytes;
  BYTE       buffer[16];
  BOOL       result;

  hServer = CreateNamedPipe("\\\\.\\pipe\\testpipe", PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED,
                            PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE | PIPE_WAIT, 
                            PIPE_UNLIMITED_INSTANCES, 0, 0, 5000, NULL);

  serverOvlp.hEvent = CreateEvent(NULL, FALSE, FALSE, NULL);

  ConnectNamedPipe(hServer, &serverOvlp);
  assert(GetLastError() == ERROR_IO_PENDING);

  hClient = CreateFile("\\\\.\\pipe\\testpipe", GENERIC_READ | GENERIC_WRITE,
                       0, NULL, OPEN_EXISTING, 0, NULL);

  GetOverlappedResult(hServer, &serverOvlp, &bytes, TRUE);

  /* Server starts an overlapped read */
//  result = ReadFile(hServer, buffer, sizeof(buffer), &bytes, &serverOvlp);
  result = ReadFileEx(hServer, buffer, sizeof(buffer), &serverOvlp, readComplete);

  if (HasOverlappedIoCompleted(&serverOvlp))
  {
    puts("Completed");
  }
  else
  {
    puts("Not completed");
  }


  return EXIT_SUCCESS;
}
4

2 に答える 2

1

あなたが求めている行動は、競合状態を伴うため、私には間違っているように思われます。この問題は、メッセージBを送信しているときにメッセージAを受信した場合にのみ発生します。現在、Aは常に無視されます。つまり、追加のメッセージは送信されません。取得しようとしている動作により、Aが到着してからBが完了するまでの間にサーバーが作業の処理でビジー状態になった場合にのみ、追加のメッセージが送信されます。常にAを無視するか、Bが完了したら常に応答を送信する必要があると思います。

ただし、それが希望どおりであることが確実な場合は、この動作を取得できます。1つの解決策は、ReadFileEx完了ルーチンからQueueUserAPCを呼び出して、応答を送信する関数への呼び出しをキューに入れることです。APCはFIFO順に実行されるため、新しいAPCは、WriteFileExがすでにキューに入れられているAPCの後に確実に実行されます。

詳細によっては、両方の完了ルーチンがフラグを設定したり、キューにアイテムを追加したりして、メインループに実際の作業を行わせる方がクリーンな場合があります。

APCをポーリングする必要がある場合(たとえば、メインループに自然に発生する待機操作がないため)、タイムアウトが0のダミーイベントでWaitForSingleObjectExを使用できます。イベントが通知されるかどうかは関係ありません。そうではなく、キューに入れられたすべてのAPCが引き続き呼び出されます。

于 2011-12-05T20:58:09.367 に答える
1

CALLBACKを実現するために、コードを少し変更しました。この例が機能するためには、パイプバッファの長さが0であってはなりません。また、パイプの両端にOVERLAPPEDフラグが設定されている必要があると思います。

#include <Windows.h>
#include <stdio.h>
#include <assert.h>

#define BUFFSIZE 100
#define MYPIPE   "\\\\.\\pipe\\testpipe"

typedef struct {
  OVERLAPPED serverOvlp;        // Overlapped should always be first in structure
  CHAR       buffer[20];
} OVLP;


VOID CALLBACK readComplete(DWORD err, DWORD bytes, LPOVERLAPPED ovlp)
{
  OVLP *temp = (OVLP *) ovlp;
  printf("readComplete  err=%d  bytes=%d  buffer=%s\n", err, bytes, temp->buffer);
}

int main(void)
{
  HANDLE     hServer;
  HANDLE     hClient;

  OVLP       oServer;

  DWORD      bytes;
  CHAR       ClientBuffer[20] = "Test message";

  hServer = CreateNamedPipe(MYPIPE, PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED,
                            PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE | PIPE_WAIT,
                            PIPE_UNLIMITED_INSTANCES, BUFFSIZE, BUFFSIZE, 5000, NULL);

//-------------------------------------- CLIENT 
  hClient = CreateFile(MYPIPE, GENERIC_READ | GENERIC_WRITE,
                       0, NULL, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL);

  WriteFile(hClient,ClientBuffer,strlen(ClientBuffer)+1,&bytes,NULL);

//-------------------------------------- SERVER
  ConnectNamedPipe(hServer, &oServer.serverOvlp);
  if (HasOverlappedIoCompleted(&oServer.serverOvlp)) assert(GetLastError() != 0 );
  puts("Client Pipe connected\n");

  ReadFileEx(hServer, oServer.buffer, sizeof(oServer.buffer), (LPOVERLAPPED)&oServer, readComplete);

  SleepEx(INFINITE,TRUE);       // Creates an alertable event so CALLBACK is triggered

  if (HasOverlappedIoCompleted(&oServer.serverOvlp)) {
    puts("Completed");
  } else {
    puts("Not completed");
  }

  return EXIT_SUCCESS;
}
于 2011-12-24T07:42:40.057 に答える