2

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

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

据我所知,何时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块相关,但它们是。对我来说pipe是一个文件句柄(就像在旧的 Turbo Pascal 中一样),它首先在某个地方定义,然后在其他地方进行操作。
4

1 回答 1

3

没有人决定哪个进程首先运行。子进程可能首先运行——或者父进程可能首先运行——操作系统可以以任何一种方式调度它们。

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

为什么没有注释行就不会发生?当您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

It waits until the child closes the pipe (then the pipe.gets will return nil), which happens then it terminates, and it ensures that it won't try to write there anymore.

于 2011-04-10T13:12:37.917 回答