我写了一个程序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。
更新:这是我到目前为止所尝试的:
b.exe
inheritancea.exe
; 这是行不通的。 MSDN特别指出,传递给CreateProcess的句柄必须是可inheritance的。 b.exe
stdout / stderr上的可inheritance标志:似乎没有任何作用(如果有的话,它会让我感到吃惊)。 ReadDataProc
过程(读取这两个pipe道)考虑除检查ERROR_BROKEN_PIPE
之外是否b.exe
实际上正在运行。 这当然不工作(但我只是后来才意识到),因为线程在ReadFile调用中被阻塞。 检查开源库libexecstream http://libexecstream.sourceforge.net/
在这种情况下发生的情况是,stdout / stderr管道的写入结束被继承到守护进程,所以管道永远不会被破坏。
守护进程应关闭其继承的文件描述符。
似乎在Windows Vista之前的Windows版本(您可以使用CancelSynchronousIO函数,没有办法使用TerminateThread终止读取线程。
一个合适的选择( 由adf88建议 )可能是使用异步ReadFile调用,但在我的情况下是不可能的(对现有代码进行太多的更改)。
设置一些全局标志(bool exit_flag)并在a.exe中写入管道