4

Win32 API を使用して、STD_INPUT_HANDLE から読み取り、読み取ったバイトをソケットにプッシュするサブスレッドを作成しようとしています。終了するときにこのスレッドを安全にシャットダウンできるようにしたいので、ReadFileEx() を使用し、単純なブロック ReadFile() の代わりにオーバーラップ I/O を使用しています。アイデアは、スレッドが ReadFile() ではなく WaitForSingleObject() で待機し、メイン スレッドがスレーブ スレッドを離れたい場合、そのオブジェクトでシグナルを送信し、スレーブ スレッドがウェイクアップして終了し、その後、メイン スレッドはシャットダウン シーケンスを続行できます。

私の問題はこれです: ReadFileEx() は非同期であり、したがってブロックされないというドキュメントにもかかわらず... 私のスレーブスレッドはまだ ReadFileEx() 内でブロックしています。(イベントループにprintfを挿入して、ブロックされている場所を確認しました)このため、メインスレッドはスレーブスレッドをシャットダウンできず、メインプログラムは終了しません。

私は何か間違ったことをしていますか、それとも ReadFileEx() は標準入力から読み取るときにブロックすることを意図していますか? 後者の場合、スレッドのシャットダウンの問題の解決策は何ですか? スレーブ スレッドのエントリ関数は、以下のとおりです。

[... in the main thread, before the slave thread is spawned...]
_stdinHandle = GetStdHandle(STD_INPUT_HANDLE);
_wakeupSignal = CreateEvent(0, false, false, 0);
[...]

VOID WINAPI CompletedReadRoutine(DWORD dwErr, DWORD cbBytesRead, LPOVERLAPPED lpOverLap)
{
   printf("CompletedReadRoutine dwErr=%li cbBytesRead=%li overlap=%p\n", dwErr, cbBytesRead, lpOverLap);
}

void StdinDataIO :: IOThreadEntry()
{
   char buf[4096];
   OVERLAPPED olap;
   bool keepGoing = true;
   bool overlappedReadPending = false;
   while(keepGoing)
   {
      if (overlappedReadPending)
      {
         DWORD waitResult = WaitForSingleObjectEx(_wakeupSignal, INFINITE, true);
         switch(waitResult)
         {
            case WAIT_IO_COMPLETION:
            {
               overlappedReadPending = false;
               DWORD numBytesRead;
               if ((GetOverlappedResult(_stdinHandle, &olap, &numBytesRead, true) == false)||(SendData(_slaveSocket, buf, numBytesRead, true) != numBytesRead)) keepGoing = false;
            }
            break;

            default:
               keepGoing = false;
            break;
         }
      }
      else
      {
         memset(&olap, 0, sizeof(olap));
         if (ReadFileEx(_stdinHandle, buf, sizeof(buf), &olap, CompletedReadRoutine)) overlappedReadPending = true;
                                                                                 else keepGoing = false;
      }
   }
   if (overlappedReadPending) CancelIo(_stdinHandle);
   _slaveSocket.Reset();  // this alerts the main thread that we are gone
}
4

1 に答える 1

4

ReadFileEx渡すことができるファイルハンドルの種類を説明するドキュメントから:

このファイル ハンドルは、FILE_FLAG_OVERLAPPED フラグを使用して作成されている必要があり、GENERIC_READ アクセス権を持っている必要があります。

それ以外の場合は、でReadFileEx開かれていないハンドルで呼び出すとブロックされますFILE_FLAG_OVERLAPPED

入力が利用可能であることを確認したい場合は、またはcallWaitForSingleObjectによって返されたハンドルまたはコンソール イベント処理のその他の組み合わせを呼び出すこともできます。GetStdHandle_kbhit

于 2009-08-22T04:52:52.560 に答える