Ruby IO.popen 带有“-” ,幕后发生了什么?
我试图理解 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 theif..else..end
block, yet they are. For mepipe
is a file handle (like in old Turbo Pascal) which is first definded somewhere, then manipulated elsewhere.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
没有人决定哪个进程首先运行。子进程可能先运行,或者父进程可能先运行,操作系统可以以任何一种方式调度它们。
这意味着父进程可能会在子进程完成之前完成。当父进程完成时,到它的管道将关闭,当子进程写入它时,它会收到异常。这就是您的代码中发生的情况。
为什么没有注释行就不会发生?当您在父进程中调用
gets
时,它会等待,直到子进程向管道写入一行。这意味着父级在子级向管道写入一行之前不会完成,而这忽略了这个问题。但是,当您打印两行时,父进程在子进程执行第二个puts "M'kay"
之前终止的可能性就会增加。尝试以下代码:
它会等到子进程关闭管道(然后
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 secondputs "M'kay"
increase.Try the following code:
It waits until the child closes the pipe (then the
pipe.gets
will returnnil
), which happens then it terminates, and it ensures that it won't try to write there anymore.