提问人:maikovich 提问时间:10/28/2023 最后编辑:maikovich 更新时间:10/28/2023 访问量:40
为什么在两个分支中关闭两个 IO 管道的顺序很重要?
Why does the order of closing two IO pipes in two forks matter?
问:
在 Ruby 中运行以下代码会无限期挂起。这似乎是因为在第一个子进程中没有被父进程解锁。Process.wait p1
r1.eof?
w1.close
r1, w1 = IO.pipe
p1 = fork { w1.close; r1.eof? }
r1.close
r2, w2 = IO.pipe
p2 = fork { w2.close; r2.eof? }
r2.close
sleep 1
w1.close
puts "Wait for p1"; Process.wait p1
w2.close
puts "Wait for p2"; Process.wait p2
我的困惑在于为什么这不起作用,以及为什么以下内容(关闭编写器并等待进程 1 和进程 2)成功执行并退出程序:
r1, w1 = IO.pipe
p1 = fork { w1.close; r1.eof? }
r1.close
r2, w2 = IO.pipe
p2 = fork { w2.close; r2.eof? }
r2.close
sleep 1
w2.close
puts "Wait for p2"; Process.wait p2
w1.close
puts "Wait for p1"; Process.wait p1
但是,一旦我将第二个片段的逻辑放在一个类中,它就不再起作用了:
class Client
def initialize
@r, @w = IO.pipe
end
def start
@pid = fork { @w.close; @r.eof? }
@r.close
end
def stop
@w.close
puts "Wait for #@pid"; Process.wait(@pid)
end
end
clients = 2.times.map { Client.new }
clients.each(&:start)
sleep 1
clients.reverse.each(&:stop)
这是怎么回事?
更深入地挖掘,并利用父进程迄今为止创建的内存中的所有文件描述符都将在分叉进程中可用的知识,我发现我可以通过将所有打开的 IO 读取器和写入器存储在一个类变量中来使其工作,并使用 关闭 fork 中所有不相关的读取器和写入器, 这样:@@opened_io
@@opened_io.reject { |io| io.closed? || io == @r }.each(&:close)
class Client
@@opened_io = []
def initialize
@r, @w = IO.pipe
@@opened_io.concat([@r, @w])
end
def start
@pid = fork do
@@opened_io.reject { |io| io.closed? || io == @r }.each(&:close)
@r.eof?
end
@r.close
end
def stop
@w.close
puts "Wait for #@pid"; Process.wait(@pid)
end
end
clients = 2.times.map { Client.new }
clients.each(&:start)
sleep 1
clients.each(&:stop)
为什么这如此重要?
答: 暂无答案
评论