【问题标题】:Can I capture stdout/stderr separately and maintain original order?我可以单独捕获 stdout/stderr 并保持原始顺序吗?
【发布时间】:2010-12-05 11:04:25
【问题描述】:

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

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

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

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

【问题讨论】:

    标签: winapi stdout redirect stderr


    【解决方案1】:

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

    【讨论】:

    • 是的,这是一种方法,但我没有足够的勇气告诉 op 太多的反对票是试图在公开论坛上这样做的必然结果。
    • 这怎么可能是真的? CMD.exe 似乎总是正确的?
    • 看起来可以,但无法知道写入了哪个流:stackoverflow.com/questions/18529662/…
    • @paulm:在某些情况下,这可能适用于某些程序,但由于上述原因,几乎可以保证至少在部分时间会失败。
    • 这就是它在 CMD 下的工作方式,如果两者使用相同的流,则保持顺序
    【解决方案2】:

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

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

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

    【讨论】:

      【解决方案3】:

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

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

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

      【讨论】:

        【解决方案4】:

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

        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(或任何立即可用的),但我希望这能说明这个概念。

        【讨论】:

          【解决方案5】:

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

          【讨论】:

            【解决方案6】:

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

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

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 2018-10-31
              • 2013-09-02
              • 1970-01-01
              • 2023-03-07
              • 1970-01-01
              • 1970-01-01
              • 2014-08-05
              • 2016-11-19
              相关资源
              最近更新 更多