我编写了一个程序a.exe
,它使用CreateProcess函数启动了我编写的另一个程序b.exe
。调用者创建两个管道,并将两个管道的写入端传递给CreateProcess,作为stdout / stderr句柄用于子进程。这几乎与MSDN上的Creating a Child Process with Redirected Input and Output样本相同。
因为它似乎无法使用一个等待进程退出stdout或stderr上的或数据的同步调用(WaitForMultipleObjects函数没有在管道上工作,调用者有两个运行的线程,它们都在stdout / stderr管道的读取端执行(阻塞)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
终止。一旦该调用返回,两个读取线程终止(因为管道坏了),并且使用CloseHandle关闭两个管道的读取端。
现在,我遇到的问题是:b.exe
可能(取决于用户输入)启动外部进程,其活动时间超过b.exe
本身,守护程序基本上处理。在这种情况下会发生的是stdout / stderr管道的写入结束继承到该守护进程,因此管道永远不会被破坏。这意味着a.exe
中的WaitForSingleObject调用返回(因为b.exe
已完成)但是对任一管道块的CloseHandle调用都是因为两个读取线程仍然位于其(阻塞!)ReadFile调用中。
如何在b.exe
返回后用蛮力(TerminateThread)终止读取线程时如何解决这个问题?如果可能的话,我也想避免任何涉及管道和/或过程轮询的解决方案。
更新:这是我到目前为止所尝试的内容:
b.exe
继承a.exe
;这不起作用。 MSDN特别声明传递给CreateProcess的句柄必须是可继承的。b.exe
内的stdout / stderr上的可继承标志:似乎没有任何效果(如果它确实会让我感到惊讶)。ReadDataProc
过程(在两个管道上读取)除了检查b.exe
之外,还要考虑ERROR_BROKEN_PIPE
是否实际运行。这当然不起作用(但之后我才意识到),因为线程在ReadFile调用中被阻止。答案 0 :(得分:2)
答案 1 :(得分:1)
在这种情况下会发生什么 写stdout / stderr的结尾 管道继承到该守护进程 过程,所以管道永远不会破裂。
守护进程应该关闭其继承的文件描述符。
答案 2 :(得分:0)
似乎在Windows Vista之前的Windows版本上(您可以使用CancelSynchronousIO函数),无法使用TerminateThread终止读取线程。
一个合适的替代方法(suggested by adf88)可能是使用异步ReadFile调用,但在我的情况下这是不可能的(对现有代码的更改要求太多)。
答案 3 :(得分:0)
设置一些全局标志(bool exit_flag)并在a.exe中写入管道