8

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

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

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

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

4

6 回答 6

3

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

于 2009-10-10T21:01:22.810 回答
2

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

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

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

于 2009-10-12T15:41:53.137 回答
0

并非如此,您会这么认为,但 std_out 由系统设计人员控制 - 究竟如何以及何时编写 std_out 取决于系统调度程序,根据我的测试,它从属于未记录的问题。

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

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

于 2009-10-09T23:37:11.677 回答
0

您可以将标准错误重定向到标准输出:

command_name 2>&1

我记得,这在 C 中使用管道是可能的。

更新:哦,对不起 - 错过了能够区分两者的部分。我知道 TextMate 使用某种用户可见代码以某种方式做到了这一点......有一段时间没看过,但我会看看它。但是经过进一步思考,您可以Open3在 Ruby 中使用类似的东西吗?您必须同时观看两者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(或任何立即可用的),但我希望这能说明这个概念。

于 2009-10-10T16:01:03.180 回答
0

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

于 2009-10-11T16:41:48.503 回答
0

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

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.

于 2009-10-12T18:30:57.567 回答