我可以单独捕获 stdout/stderr 并保持原始顺序吗?

发布于 2024-08-07 11:57:41 字数 377 浏览 9 评论 0原文

我使用本机 win32 API 编写了一个 Windows 应用程序。我的应用程序将启动其他进程并捕获输出并以红色突出显示 stderr 输出。

为了实现这一点,我为 stdout 和 stderr 创建一个单独的管道,并在调用 CreateProcess 时在 STARTUPINFO 结构中使用它们。然后,我为每个 stdout/stderr 句柄启动一个单独的线程,该线程从管道读取并将输出记录到窗口。

这在大多数情况下都可以正常工作。我遇到的问题是,如果子进程快速连续记录到 stderr 和 stdout,我的应用程序有时会以错误的顺序显示输出。我假设这是由于使用两个线程从每个句柄读取数据造成的。

是否可以按照写入的原始顺序捕获 stdout 和 stderr,同时能够区分两者?

I've written a Windows application using the native win32 API. My app will launch other processes and capture the output and highlight stderr output in red.

In order to accomplish this I create a separate pipe for stdout and stderr and use them in the STARTUPINFO structure when calling CreateProcess. I then launch a separate thread for each stdout/stderr handle that reads from the pipe and logs the output to a window.

This works fine in most cases. The problem I am having is that if the child process logs to stderr and stdout in quick succession, my app will sometimes display the output in the incorrect order. I'm assuming this is due to using two threads to read from each handle.

Is it possible to capture stdout and stderr in the original order they were written to, while being able to distinguish between the two?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(6

娇柔作态 2024-08-14 11:57:42

我很确定这是不可能完成的,除非编写生成的程序来写入数据包并为每个数据包添加时间戳。如果没有这个,您通常可以计划在子进程的标准库中进行缓冲,因此当它们甚至通过管道传输到父进程时,它们很可能已经乱序了。

I'm pretty sure it can't be done, short of writing the spawned program to write in packets and add a time-stamp to each. Without that, you can normally plan on buffering happening in the standard library of the child process, so by the time they're even being transmitted through the pipe to the parent, there's a good chance that they're already out of order.

夜司空 2024-08-14 11:57:42

在我见过的大多数 stdout 和 stderr 实现中,stdout 是缓冲的,而 stderr 不是。基本上,这意味着即使在直接命令行上运行程序,也不能保证它们会按顺序排列。

http://en.wikipedia.org/wiki/Stderr#Standard_error_.28stderr。 29

简短的回答:您无法确保按照 cmd.exe 中出现的顺序读取这些行,因为无法保证它们在 cmd.exe 中出现的顺序。

In most implementations of stdout and stderr that I've seen, stdout is buffered and stderr is not. Basically what this means is that you aren't guaranteed they're going to be in order even when running the program on straight command line.

http://en.wikipedia.org/wiki/Stderr#Standard_error_.28stderr.29

The short answer: You cannot ensure that you read the lines in the same order that they appear on cmd.exe because the order they appear on cmd.exe is not guaranteed.

如何视而不见 2024-08-14 11:57:42

事实并非如此,您可能会这么认为,但 std_out 是由系统设计者控制的 - std_out 的具体写入方式和时间取决于系统调度程序,根据我的测试,系统调度程序从属于未记录的问题。

有一天,我正在写一些东西,并在系统上的一个设备上做了一些工作,同时我在编辑器中打开代码,发现系统为驱动程序提供了实时优先级,留下了我精心设计的 c-某个地方的代码大约是专有代码的十分之一。

至少可以说,重新反转它以便获得写入的顺序顺序将是具有挑战性的。

Not really, you would think so but std_out is at the control of the system designers - exactly how and when std_out gets written is subject to system scheduler, which by my testing is subordinated to issues that are not as documented.

I was writing some stuff one day and did some work on one of the devices on the system while I had the code open in the editor and discovered that the system was giving real-time priority to the driver, leaving my carefully-crafted c-code somewhere about one tenth as important as the proprietary code.

Re-inverting that so that you get sequential ordering of the writes is gonna be challenging to say the least.

醉态萌生 2024-08-14 11:57:42

您可以将 stderr 重定向到 stdout:

command_name 2>&1

我记得这在 C 中可以使用管道实现。

更新:哦,抱歉——错过了关于能够区分两者的部分。我知道 TextMate 使用某种用户可见的代码以某种方式做到了这一点...有一段时间没看过,但我会看一下。但经过进一步思考,您可以在 Ruby 中使用类似 Open3 的东西吗?您必须同时观看 STDOUTSTDERR,但实际上没有人应该期望这两者的输出有一定的顺序。

更新 2:我在 Ruby 中的含义示例:

require 'open3'

Open3.popen3('ruby print3.rb') do |stdin, stdout, stderr|
  loop do
    puts stdout.gets
    puts stderr.gets
  end
end

...其中 print3.rb 只是:

loop do
  $stdout.puts 'hello from stdout'
  $stderr.puts 'hello from stderr'
end

您可以将消息发送到一个观察者,它将在你的程序中打印出来。抱歉,我的这台机器上没有 Windows(或任何立即可用的),但我希望这能说明这个概念。

You can redirect stderr to stdout:

command_name 2>&1

This is possible in C using pipes, as I recall.

UPDATE: Oh, sorry -- missed the part about being able to distinguish between the two. I know TextMate did it somehow using kinda user visible code... Haven't looked for a while, but I'll give it a peek. But after some further thought, could you use something like Open3 in Ruby? You'd have to watch both STDOUT and STDERR at the same time, but really no one should expect a certain ordering of output regarding these two.

UPDATE 2: Example of what I meant in Ruby:

require 'open3'

Open3.popen3('ruby print3.rb') do |stdin, stdout, stderr|
  loop do
    puts stdout.gets
    puts stderr.gets
  end
end

...where print3.rb is just:

loop do
  $stdout.puts 'hello from stdout'
  $stderr.puts 'hello from stderr'
end

Instead of throwing the output straight to puts, you could send a message to an observer which would print it out in your program. Sorry, I don't have Windows on this machine (or any immediately available), but I hope this illustrates the concept.

不…忘初心 2024-08-14 11:57:42

我非常确定,即使您根本将它们分开,您仍然不能保证它们会以正确的顺序相互交换。

I'm pretty sure that even if you don't separate them at all, you're still not guaranteed that they'll interchange one another in the correct order.

浊酒尽余欢 2024-08-14 11:57:42

由于目的是注释现有程序的输出,因此两个流的任何可能的交错都必须正确。原始开发人员将放置适当的flush()调用以确保遵守任何强制顺序。

如前所述,记录用时间戳写入的每个片段,并使用它来恢复输出设备实际看到的序列。

Since the intent is to annotate the output os an existing program, any possible interleaving of the two streams must be correct. The original developer will have placed appropriate flush() calls to ensure any mandatory ordering is honoured.

As previously explained, record each fragment that is written with a time stamp, and use this to recover the sequence actually seen by the output devices.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文