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

时间:2009-10-09 19:20:32

标签: winapi stdout redirect stderr

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

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

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

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

6 个答案:

答案 0 :(得分:3)

我很确定它无法完成,只需编写生成的程序来写入数据包并为每个程序添加时间戳。如果没有这个,你通常可以计划在子进程的标准库中进行缓冲,所以当它们甚至通过管道传输给父进程时,它们很可能已经出现故障。< / p>

答案 1 :(得分:2)

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

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

简短回答:您无法确保以与cmd.exe上显示的顺序相同的顺序读取这些行,因为它们在cmd.exe上的显示顺序无法保证。

答案 2 :(得分:0)

不是真的,你会这么认为,但std_out是由系统设计师控制的 - 确切地说std_out的编写方式和时间是由系统调度程序决定的,我的测试通过系统调度程序从属于未记录的问题。

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

重新反转这一点,以便你顺序排列写入,至少可以说具有挑战性。

答案 3 :(得分:0)

您可以将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

您可以向观察者发送消息,而不是将输出直接输出到puts,而观察者会在程序中将其打印出来。对不起,我在这台机器上没有Windows(或任何立即可用的),但我希望这说明了这个概念。

答案 4 :(得分:0)

我很确定即使你将它们分开,你仍然无法保证它们会以正确的顺序相互交换。

答案 5 :(得分:0)

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

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