2009-08-22 8 views
3

私は、Win32 APIを使ってSTD_INPUT_HANDLEから読み込んだサブスレッドを作成し、読み込んだバイトをソケットにプッシュしようとしています。終了するときにこのスレッドを安全にシャットダウンできるようにするために、私はReadFileEx()を使用していて、プレーンな古いReadFile()の代わりにI/Oをオーバーラップしています。私のスレッドは、ReadFile()ではなくWaitForSingleObject()で待機し、メインスレッドがスレーブスレッドを遠ざけたい場合、そのオブジェクトに信号を送り、スレーブスレッドが起動して終了します。メインスレッドはシャットダウンシーケンスを続けることができます。Win32:STD_IN_HANDLEブロックのReadFileEx()はなぜですか?

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

私は何か間違っているのですか、またはReadFileEx()がstdinから読み込むときにブロックすることを意味していますか?後者の場合、スレッドシャットダウン問題の解決策は何ですか?スレーブスレッドのエントリ関数は、あなたのpersualについては、以下である...

[... 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 
} 

答えて

3

あなたが渡すことができ、ファイルハンドルのどのような記述ReadFileExのドキュメントから:このファイルハンドルが が作成されている必要があり

FILE_FLAG_OVERLAPPED フラグを使用し、GENERIC_READ アクセス権が必要です。

FILE_FLAG_OVERLAPPEDで開かれていないハンドルで呼び出すと、ReadFileExがブロックされます。

GetStdHandleによって返されたハンドルでWaitForSingleObjectまたはその他の同期機能を呼び出して、などのコンソールイベント処理の組み合わせを使用して、入力が有効であることを確認することができます。

+0

私は恐れていました。私はキーボードからだけでなく、親プロセスやファイルのリダイレクトも読むことができる必要があるので、CONIN $のトリックが私が望むことをするとは思わない –