代码之家  ›  专栏  ›  技术社区  ›  flashk

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

  •  8
  • flashk  · 技术社区  · 16 年前

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

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

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

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

    6 回复  |  直到 16 年前
        1
  •  3
  •   Jerry Coffin    16 年前

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

        2
  •  2
  •   Evan Larkin    16 年前

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

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

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

        3
  •  0
  •   Nicholas Jordan    16 年前

    不是真的,你会这么认为,但是std-out是由系统设计者控制的——准确地说,std-out是如何以及何时被写入的,取决于系统调度程序,通过我的测试,它服从于那些没有文档记录的问题。

    有一天,我写了一些东西,在系统上的一个设备上做了一些工作,当时我在编辑器中打开了代码,发现系统对驱动程序给予了实时优先权,所以我精心编制的C代码大约和专有代码一样重要。

    把它颠倒过来,这样你就可以得到写操作的顺序,这至少是一个挑战。

        4
  •  0
  •   Benjamin Oakes    16 年前

    您可以将stderr重定向到stdout:

    command_name 2>&1

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

    更新:哦,抱歉——错过了区分两者的部分。我知道textmate是用某种用户可见的代码做的…好久没找了,不过我会看一眼的。但是经过进一步的思考,你能用一下吗 Open3 红宝石?你两个都得看 STDOUT STDERR 同时,但实际上没有人应该期望这两个方面的输出有一定的顺序。

    更新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
  •  0
  •   shoosh    16 年前

    我很确定即使你 不要 把它们分开,你仍然不能保证它们会按正确的顺序互相交换。

        6
  •  0
  •   Pekka    16 年前

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

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

    推荐文章