如何在单个ruby脚本中写入和读取同一命名管道?

时间:2019-02-27 04:00:46

标签: ruby multithreading fork race-condition

编辑:我想我已经解决了这个问题:https://gist.github.com/niuage/c0637b8dd10549a12b6a223dbd5f158a

我可能一直缺少Process.wait,因此创建了很多僵尸进程。


我有一段大部分时间都在工作的代码,但是一段时间后可能会因为竞争状况而“锁定”自身。

我的代码

pipe = "goals.png"

(1..100).each do |time|
  fork do
    # This runs ffmpeg, and gets it to write 1 frame of a video to the pipe 'goals.png'
    print "before ffmpeg"
    `#{ffmpeg(time, score_crop_options, pipe)}`
    exit
  end

  # Reads from 'pipe'
  print "before read"
  blob = File.read(pipe)
  image = Rocket::Image.from_blob(blob)
  # do stuff with image
end

注意事项:

  • #{ffmpeg(time, pipe)}写入管道,并一直阻塞,直到从管道读取某些内容为止

  • File.read(pipe)处于阻塞状态,直到有东西写入到管道中

我的问题

edit:脚本被锁定时,当我尝试从另一个脚本读取管道时,得到zsh: fork failed: resource temporarily unavailable。这可能是个好主意...

在大多数情况下,File.read(pipe)在fork的代码之前执行,因此效果很好,但是过一会儿脚本便停止了:它显示"before ffmpeg"且从未到达{{1 }} ...


首先,我应该使用线程而不是fork吗?我是否可以控制2条语句(读和写)的运行顺序,以避免出现竞争状况?也许甚至与比赛条件无关,我还缺少一些东西?

1 个答案:

答案 0 :(得分:0)

问题不是由竞争状况引起的,而是僵尸进程过多,因为我没有打电话给Process.wait

  

父进程应该使用Process.wait来收集其子进程的终止状态,或者使用Process.detach来注册对其状态不感兴趣的对象;否则,操作系统可能会累积僵尸进程。

这就是为什么当我尝试从另一个脚本中的管道读取时得到zsh: fork failed: resource temporarily unavailable的原因。

这是行得通的:

(1..100) do
  if fork
    # Parent
    image = read_image(pipe)
    # do stuff with image

    Process.wait # I think that's what was missing previously
  else
    # Child
    Open3.popen3(command(time, score_crop_options, pipe)) do |stdin, stdout, stderr, wait_thr|
      # stuff
    end
    exit!(0)
  end
end