Search code examples
rubyiopipeeoferror

Ruby readpartial on IO.pipe won't raise EOFError


I am trying to understand how the IO.pipe in Ruby works, In the example below, I send data to the io pipe and close the stream after I finish sending the data. In a child process, I read the data using the readpartial method. According to the docs readpartial should raise EOFError when the stream is closed, but I end up with a blocked process instead, Am I understanding it right?

# ruby 2.6.3
r, w = IO.pipe

pid = fork do
  loop do
    puts r.readpartial(1024)
    sleep 0.1
  rescue EOFError
    puts "End of File"
    break
  end
end

1000.times do |t|
  w.write "xyz #{t}"
end

w.close

Process.wait(pid)

Solution

  • You need to close the write end of the pipe in the child as well as in the parent.

    After you fork you effectively have two write ends and two read ends to the pipe. When you close the write end in the parent the write end in the child is still open, so the call to readpartial will block.

    You just need to call w.close immediately after forking in the child:

    pid = fork do
      w.close
      loop do
        #...
    

    You would normally also immediately close the read end in the parent after forking (although in this case it doesn’t really matter):

    pid = fork do
      #...
    end
    
    r.close