禁用重定向 stdout 管道上的缓冲(Win32 API、C++)
我使用 CreateProcess
从 Win32 生成一个进程,将 STARTUPINFO
的 hStdOutput
和 hStdError
属性设置为管道句柄使用CreatePipe
创建。我有两个线程正在读取管道,等待数据可用(或进程完成,此时它会检查在终止线程之前是否没有剩余数据)。
当数据可用时,我将输出有效地写到一个大文本框中。
发生的情况是输出正在缓冲,因此运行缓慢的进程只会获取在文本框中抛出的数据块,而不是“当它发生时”。
我不确定是否是管道在进行缓冲,或者与重定向有关。
有没有办法将管道设置为无缓冲,或者以尽快发送标准输出的方式启动进程?
我正在使用一个测试应用程序进行测试,该应用程序每隔一秒打印一行
Here is line one
(waits one second)
Here is line two
(waits one second)
... etc
I'm spawning a process from Win32 using CreateProcess
, setting the hStdOutput
and hStdError
properties of STARTUPINFO
to pipe handles created with CreatePipe
. I've got two threads reading the pipes, waiting for data to become available (or the process to complete, at which point it checks that there is no data left before terminating the thread).
As data becomes available, I write the output out to effectively a big textbox.
What's happening is the output is being buffered, so a slow running process just gets chunks of data thrown at the text box, but not "as it happens".
I'm not sure if it's the pipe that's doing the buffering, or something to do with the redirection.
Is there any way to either set the pipe to be unbuffered, or start the process in such a way that the stdout is sent as soon as possible?
I'm testing with a test app that prints lines one second apart
Here is line one
(waits one second)
Here is line two
(waits one second)
... etc
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
缓冲可能在 C 运行时(printf 等)中,您对此无能为力(IIRC 它会执行 isatty() 检查以确定缓冲策略)
The buffering is probably in the C runtime (printf etc) and there is not much you can do about it (IIRC it does a isatty() check to determine a buffering strategy)
就我而言,缓冲位于客户端的输出中(如 @Anders 所写),它使用普通的 printf。也许这也取决于 C 运行时 (Visual Studio 2019) 的实现,也许运行时检测到“不是控制台”并启用缓冲。
所以我通过这个调用禁用了缓冲
setvbuf(stdout, (char*)NULL, _IONBF, 0);
在我的客户端中,现在我立即在服务器的管道中获得输出。只是为了完整性:这是我读取服务器中管道的方式
In my case the buffering was in the output of the client (as @Anders wrote), which uses normal
printf
. Maybe this also depends on the implementation of the C runtime (Visual Studio 2019), maybe the runtime detects 'not a console' and enables buffering.So I disabled the buffering with this call
setvbuf(stdout, (char*)NULL, _IONBF, 0);
in my client, now I get the output immediately in the pipe in the server.Just for completeness: Here's how I read the pipe in the server
有 SetNamedPipeHandleState,但它只控制远程管道的缓冲,而不是当两端都在同一台计算机上。
There's SetNamedPipeHandleState, but it only controls buffering for remote pipes, not when both ends are on the same computer.
在我看来,如果将
STARTUPINFO
的hStdOutput
和hStdError
设置为管道句柄,就可以解决问题使用CreatePipe
创建,而不是创建一个命名管道(使用CallNamedPipe
函数,与之前使用的CallNamedPipe
函数完全相同,如果之前还使用 SECURITY_ATTRIBUTES 和bInheritHandle
=TRUE
,请参阅 http://msdn.microsoft。 com/en-us/library/aa365782.aspx),然后使用FILE_FLAG_WRITE_THROUGH
标志根据CreateFile
的名称打开那里。就像您可以在 MSDN (http://msdn.microsoft.com/ en-us/library/aa365592.aspx):因此,只需使用
FILE_FLAG_WRITE_THROUGH
标志重新打开与CreateFile
相关的管道,并将句柄设置为hStdOutput
和hStdError
STARTUPINFO
。It seems to me you can solve the problem if you set the
hStdOutput
andhStdError
ofSTARTUPINFO
not to pipe handles created withCreatePipe
, but instead of that you create a named pipes (withCallNamedPipe
function exactly like you used if before also using SECURITY_ATTRIBUTES withbInheritHandle
=TRUE
, see http://msdn.microsoft.com/en-us/library/aa365782.aspx) and then open there by name with respect ofCreateFile
usingFILE_FLAG_WRITE_THROUGH
flag. Like you can read on the MSDN (http://msdn.microsoft.com/en-us/library/aa365592.aspx):So just reopen the pipe with respect of
CreateFile
usingFILE_FLAG_WRITE_THROUGH
flag and set the handle/handles tohStdOutput
andhStdError
ofSTARTUPINFO
.