如何正确读取subprocess的stdout / stderr输出?

我写了一个程序a.exe ,它使用CreateProcess函数启动另一个我写的程序b.exe 。 调用者创build两个pipe道,并将两个pipe道的写入端传递给CreateProcess,作为stdout / stderr句柄用于subprocess。 这与在MSDN上创build具有redirectinput和输出样本的subprocess几乎相同。

由于它似乎不能使用一个等待进程退出的同步调用 stdout或stderr上的数据可用( WaitForMultipleObjects函数在pipe道上不起作用),调用者有两个线程正在运行都在stdout / stderrpipe道的读取端执行(阻塞) ReadFile调用; 这里是用于stdout / stderr的“读取线程过程”的确切代码(我没有自己写这个代码,我假设有一些同事呢):

 DWORD __stdcall ReadDataProc( void *handle ) { char buf[ 1024 ]; DWORD nread; while ( ReadFile( (HANDLE)handle, buf, sizeof( buf ), &nread, NULL ) && GetLastError() != ERROR_BROKEN_PIPE ) { if ( nread > 0 ) { fwrite( buf, nread, 1, stdout ); } } fflush( stdout ); return 0; } 

a.exe然后使用一个简单的WaitForSingleObject调用来等待,直到b.exe终止。 一旦该调用返回,两个读取线程就会终止(因为pipe道已损坏),并且使用CloseHandleclosures两个pipe道的读取结束。

现在,我遇到的问题是: b.exe 可能 (取决于用户input)启动外部进程比b.exe本身寿命更长,守护进程基本上。 在这种情况下发生的情况是,stdout / stderrpipe道的写入结束被inheritance到守护进程,所以pipe道永远不会被破坏。 这意味着a.exe中的WaitForSingleObject调用将返回(因为b.exe完成),而是任一pipe道块上的CloseHandle调用,因为两个读取线程仍处于其阻塞的ReadFile调用中。

我怎样才能解决这个问题,而没有在b.exe返回后用蛮力( TerminateThread )终止两个阅读线程? 如果可能的话,我想避免任何涉及pipe道和/或过程轮询的解决scheme。

更新:这是我到目前为止所尝试的:

  1. 没有b.exeinheritancea.exe ; 这是行不通的。 MSDN特别指出,传递给CreateProcess的句柄必须是可inheritance的。
  2. 清除b.exe stdout / stderr上的可inheritance标志:似乎没有任何作用(如果有的话,它会让我感到吃惊)。
  3. ReadDataProc过程(读取这两个pipe道)考虑除检查ERROR_BROKEN_PIPE之外是否b.exe实际上正在运行。 这当然不工作(但我只是后来才意识到),因为线程在ReadFile调用中被阻塞。

检查开源库libexecstream http://libexecstream.sourceforge.net/

  1. 使用命名管道和异步ReadFile
    要么
  2. 解析从管道中读取的输出结果(在你的情况下可能太复杂了)。

在这种情况下发生的情况是,stdout / stderr管道的写入结束被继承到守护进程,所以管道永远不会被破坏。

守护进程关闭其继承的文件描述符。

似乎在Windows Vista之前的Windows版本(您可以使用CancelSynchronousIO函数,没有办法使用TerminateThread终止读取线程。

一个合适的选择( 由adf88建议 )可能是使用异步ReadFile调用,但在我的情况下是不可能的(对现有代码进行太多的更改)。

设置一些全局标志(bool exit_flag)并在a.exe中写入管道