Ruby IO.popen 带有“-” ,幕后发生了什么?

发布于 2024-10-31 04:29:17 字数 975 浏览 1 评论 0原文

我试图理解 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 中一样),它首先在某个地方定义,然后在其他地方进行操作。

I'm trying to understand IO.popen when its command is "-" which starts a new Ruby interpreter.

There is not much material about this subject, and I'm getting slowly through them, mainly because of me as I only code for fun.

As far as I have understood when IO.popen("-", "w+") {|f| ...} is invoked - that's with a block - that block will be run by both the parent and the child process. The difference is that the parent process will get an IO object as a result, but the child gets only a Nil. That's easy, I need to check |f| in the block and when it is Nil, execution is in the child process, when it is not nil, execution is in the parent. So I have to write both code for parent and child separated by if.

This time it helps me to understand the problem, that the block is part of the IO.popen command.

I have this code:

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

Questions:

  • What decides which process runs first? If they were to append a file would it be vulnerable to race condition?
  • Why the 2nd line breaks the code? The pipe = IO.popen... command shouldn't be related to the if..else..end block, yet they are. For me pipe is a file handle (like in old Turbo Pascal) which is first definded somewhere, then manipulated elsewhere.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

夏至、离别 2024-11-07 04:29:17

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

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

为什么没有注释行就不会发生?当您在父进程中调用 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),然后它终止,并确保它获胜不要再尝试在那里写信了。

No one decides which process runs first. The child process may run first—or the parent process may run first—OS may schedule them either way.

This means that parent process may finish before the child process finishes. When parent process finishes, the pipe to it is closed, and when the child process writes to it, it gets an exception. That's what happens in your code.

Why doesn't it happen without the commented line? When you invoke gets in the parent process, it waits until the child writes a line to the pipe. It means that the parent won't finish until the child writes a line to the pipe, and this neglects the issue. However, when you print two lines, the odds that the parent process terminates before the child executes the second puts "M'kay" increase.

Try the following code:

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.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文