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

Ruby IO.popen with “-” , what happens under the hood?

我试图理解io.popen的命令是"-",它启动了一个新的Ruby解释器。

关于这个主题没有太多的材料,我正在慢慢地理解它们,主要是因为我只是为了好玩而编写代码。

据我所知,当调用IO.popen("-","w+") {|f| ...}时(即使用块),该块将由父进程和子进程运行。不同的是,父进程将得到一个IO对象,但子进程只得到一个零。这很简单,我需要在块中检查|f|,如果为nil,则执行在子进程中,如果不是nil,则执行在父进程中。因此,我必须编写由if分隔的父代和子代代码。

这一次,它帮助我理解这个问题,这个块是io.popen命令的一部分。

我有这个代码:

1
2
3
4
5
6
7
8
9
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中一样),它首先在某个地方定义,然后在其他地方操作。

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

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

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

尝试以下代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
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),然后它终止,并确保它不再尝试在那里写入。