Ruby IO.popen带“ - ”,引擎盖下会发生什么?

时间:2011-04-10 12:37:48

标签: ruby io subprocess popen ruby-1.9.2

当我的命令为"-"并启动一个新的Ruby解释器时,我试图理解IO.popen。

关于这个主题的材料并不多,我慢慢地通过它们,主要是因为我,因为我只是为了好玩而编码。

据我所知,IO.popen("-", "w+") {|f| ...}被调用时 - 带有一个块 - 该块将由两者运行父进程和子进程。不同之处在于父进程将获得一个IO对象,但子进程只有Nil。这很简单,我需要检查块中的|f|,当它是Nil时,执行是在子进程中,当它不是nil时,执行在父进程中。因此,我必须为if分隔的父和子代码编写。

这一次有助于我理解这个问题,该块是IO.popen命令的一部分

我有这段代码:

pipe = IO.popen("-","w+")
# puts "This line will break functionality if uncommented"
  if pipe != nil then
    pipe.puts "PID: #{Process.pid}"
    $stderr.puts "Parent from child: #{pipe.gets.chomp}"
  else
    $stderr.puts "Child PID: #{Process.pid} and Parent #{gets.chomp}"
    puts "M'kay"
  end

问题:

  • 什么决定哪个进程先运行?如果他们要附加一个档案,那么它是否容易受到竞争条件的影响?
  • 为什么第二行会破坏代码? pipe = IO.popen...命令不应与if..else..end块相关,但它们是。{1}}。对我来说,pipe是一个文件句柄(就像在旧的Turbo Pascal中一样),它首先在某处定义,然后在别处操作。

1 个答案:

答案 0 :(得分:2)

没有人决定首先运行哪个进程。子进程可以先运行 - 或者父进程可以先运行 - 操作系统可以按任意方式安排它们。

这意味着父进程可以在子进程完成之前完成。当父进程完成时,它的管道被关闭,当子进程写入它时,它会得到一个异常。这就是你的代码中发生的事情。

为什么没有评论线就不会发生?在父进程中调用gets时,它会一直等到子进程向管道写入一行。这意味着在孩子将一条线写入管道之前父母不会完成,这忽略了问题。但是,当您打印两行时,父进程在子项执行第二次 puts "M'kay"之前终止的几率。

请尝试以下代码:

pipe = IO.popen("-","w+")
puts "This line will not break functionality"
puts "This line will not break functionality"
puts "This line will not break functionality"
  if pipe != nil then
    pipe.puts "PID: #{Process.pid}"
    while line = pipe.gets
      $stderr.puts "Parent from child: #{line.chomp}"
    end
  else
    $stderr.puts "Child PID: #{Process.pid} and Parent #{gets.chomp}"
    puts "M'kay"
  end

它等待孩子关闭管道(然后pipe.gets将返回nil),然后它会终止,并且它确保它不会再尝试在那里写。