2015-04-24 107 views
1

我目前正在潜入Win32 API并编写自己的包装类CreateProcessCreatePipe。我只是想知道如果我打开的进程为管道缓冲区写入太多输出,将会发生什么情况。这个过程是否会等到我从管道的另一端读取? CreatePipe函数备注建议如此:如果管道已满,是否会写入管道块的进程?

当进程使用WriteFile写入匿名管道时,直到写入所有字节才完成写入操作。如果在写入所有字节之前管道缓冲区已满,则WriteFile将不会返回,直到其他进程或线程使用ReadFile来提供更多缓冲区空间。

https://msdn.microsoft.com/en-us/library/windows/desktop/aa365152%28v=vs.85%29.aspx

假设我开一个进程,CreateProcess,然后用WaitForSingleObject等到进程退出。如果超过标准输出管道的缓冲区大小,该进程是否会退出?

+1

如果官方的参考文献说'WriteFile'函数“不会返回......”,它与阻塞相同。那么答案是,是写入一个完整的管道会阻塞。顺便说一句,它是例如POSIX系统(如Linux或OSX)也是如此。 –

+1

在POSIX系统中,这确实发生了什么:生产者被阻塞,直到有空间写入。例如,当你做'ls -R/|时less“,'less'将读取文本的某些屏幕,然后阻止'ls',直到用户向下滚动。如果用户杀死读者进程(例如通过退出'less'),则原始进程将被终止。这可以节省大量无用的计算。 – anol

+1

“不返回”==块。如果你不读取重定向输出,那么,这个过程很可能会陷入僵局。一个非常标准的错误是消耗stdout而不是stderr。您需要在所有3个句柄上使用WaitForMultipleObjects()。 –

回答

3

WaitForSingleObject关于重定向输出的进程确实是一个死锁。您需要保持输出管道畅通,以便让子进程运行完成。

通常你会使用重叠在管的I/O,然后WaitForMultipleObjects上在循环手柄对(处理句柄,管道读取事件句柄),直到处理手柄变得信号通知。

雷蒙德陈写的情况下,当输入管道输送:


汉斯·评论说,可以有一个以上的输出流。 stdoutstderr是典型的,通过处理继承可能更多。排除流程中出现的所有管道。

+0

感谢您提供丰富的答案。我还有一个问题:当我在为进程创建的所有管道上调用'CloseHandle'时,是否仍然会发生死锁或者我可以安全地调用'WaitForSingleObject'?我想添加一个'Wait()'方法,它将简单地忽略进程产生的任何输出,但会阻塞直到它终止。 –

+0

你问关于CloseHandle是父进程还是子进程?这将防止死锁,但管道的另一端在尝试写入或零字节读取时会遇到错误。 –

+0

在父进程中。在“子进程中的句柄”中,是否指的是我在'STARTUPINFO'结构中指定的句柄?假设子进程从标准输入中读取并从父进程中关闭它,那么子进程是否会遇到错误,或者它会在标准输入管道中只读取什么(或剩下的内容)? –