2016-05-16 16 views
1

を私はstdinHandle = GetStdHandle(STD_INPUT_HANDLE)を経由して得たハンドルを持っていると私は、このようなコードを実行する別のスレッドを持っている:timeToExitstd::atomic<bool>あるのWin32:ReadFile関数を停止する方法(STDIN |パイプ)

while (!timeToExit) { 
    char ch; 
    DWORD readBytes = 0; 
    if (!::ReadFile(stdinHandle, &ch, sizeof(ch), &readBytes, nullptr)) { 
    //report error 
    return; 
    } 
    if (readBytes == 0) 
     break; 
    //handle new byte 
} 

他のスレッドからこのスレッドを停止することもできます。私はこれを試みた:

timeToExit = true; 
CloseHandle(stdinHandle); 

そしてコードはCloseHandleでハングアップします。

CreatePipeDuplicateHandleを使用して他のプログラムでプログラムを実行しているときにコードがハングし、自分のプログラムの入力をパイプにリダイレクトします。

したがって、私はスレッドをwin32の方法で停止する必要がありますか? または私はいくつかの方法を変更する必要がありますwhile (!timeToExit).. それを停止するスレッドを可能にするには?

更新 は、私は、引数として stdinとイベントにReadFileの呼び出しの前WaitForMultipleObjectsの使用について考え、そして他のスレッドでイベントをトリガし、 しかしWaitForMultipleObjectsのための可能な入力として匿名パイプについての言及はない、プラスI コンソールにstdinを接続しようとしたときに、最初の文字がコンソールに入力された後で無駄になります( )ReadFileの代わりにReadConsoleInputを使用する必要がありますか?

+0

WaitForMultipleObjects()は、名前の付いたパイプと名前のないパイプとコンソールも処理できます。私のプログラムを実行するプロセスは、標準入力を「パイプ」に0バイトを書く場合 – wilx

+0

@wilxは 'WaitForMultipleObjects'は奇妙な方法で物事を処理し、それは' WAIT_OBJECT_0'(最初の呼び出し後に)返しますが、 'ReadFile'も、1バイトを読み取ることができません私は問題の問題に戻ります。入力を待つ 'ReadFile'があります。 – fghj

+0

0バイトを書き込まないでください。 – wilx

答えて

4

コンソールの実際のSTDINから読み取るときは、ReadFile()の代わりにPeekConsoleInput()ReadConsoleInfo()を使用できます。

(un)名前付きパイプから読み取る場合は、ReadFile()を呼び出す前にPeekNamedPipe()を使用してください。

これにより、STDINを実際に読み取る前に新しい入力をポーリングすることができます。次に、ポーリング間でスレッド終了ステータスを確認できます。

を使用して、STD_INPUT_HANDLEハンドルにどのような種類のデバイスが接続されているかを検出できます。

+0

ありがとうございます、今は期待どおりに動作します。 – fghj

-2

これを行う最も安全な方法は、OVERLAPPED構造体などを使用してReadFileを非同期(非ブロック)にすることです。これはメインスレッドから行うことができます。

キャンセルする必要がある場合は、CancelIo(ReadFileと同じスレッド)またはCancelIoEx(別のスレッドの場合)を呼び出します。

現在のアプローチを有効にすることができます。 timeToExitをvolatileとマークすると、ハングしないかもしれませんが、そのアプローチは一般的に大きな問題を引き起こします。

+2

OVERLAPPED IOがコンソールで動作していないか、何かが見つかりませんでしたか?たとえば、CreateFile msdnページには、フラグが無視されるコンソールに関する特別な注意があり、重複したフラグでstdinを開くことはできません。私は何かを逃したことがありますか? – fghj