Using Ruby 2.5's IO#close

Ruby 2.5 was recently released.

IO class is the basis for all input and output. You can use the public methods of IO class to open, write, read and close the IO stream. The close method makes the IO stream unavailable for any further data operations.  Ruby’s IO#close which would earlier raise an error with message “stream closed”, but it is refined to “stream closed in another thread”. The new message is more clear for the user.

read_io, write_io = IO.pipe
thread = Thread.new do
  read_io.read
end
read_io.close
write_io.close
thread.join

Ruby 2.4.0

➜  ~ ruby io_ruby.rb
io_ruby.rb:3:in `read': closed stream (IOError)
        from io_ruby.rb:3:in `block in <main>'

Ruby 2.5.0

➜  ~ ruby io_ruby.rb
#<Thread:[email protected]_ruby.rb:2 run> terminated with exception (report_on_exception is true):
Traceback (most recent call last):
        1: from io_ruby.rb:3:in `block in <main>'
io_ruby.rb:3:in `read': closed stream (IOError)
Traceback (most recent call last):
        1: from io_ruby.rb:3:in `block in <main>'
io_ruby.rb:3:in `read': closed stream (IOError)

In the above example we close the read stream before the thread has finished its execution and an IOError is raised with message “closed stream” for both Ruby 2.4.0 & Ruby 2.5.0.

Didn’t we try to close the stream in other thread besides the main ruby thread? No, I don’t think we did. Can we tell the thread scheduler that “hey, please pass the execution to another thread other than the one which is currently running”? Yes, we can using 

Thread.pass

Lets update our program

read_io, write_io = IO.pipe
thread = Thread.new do
  read_io.read
end
Thread.pass
read_io.close
write_io.close
thread.join

Ruby 2.4.0

io_ruby.rb:3:in `read': closed stream (IOError)
        from io_ruby.rb:3:in `block in <main>'

Ruby 2.5.0

#<Thread:[email protected]_ruby.rb:2 run> terminated with exception (report_on_exception is true):
Traceback (most recent call last):
        1: from io_ruby.rb:3:in `block in <main>'
io_ruby.rb:3:in `read': closed stream (IOError)
Traceback (most recent call last):
        1: from io_ruby.rb:3:in `block in <main>'
io_ruby.rb:3:in `read': closed stream (IOError)

Why aren’t we getting “stream closed in another thread” error message? Is our thread sleeping or dead? We should also check if the our thread is dead or sleeping.

#<Thread:[email protected]_ruby.rb:2 run> terminated with exception (report_on_exception is true):
read_io, write_io = IO.pipe
thread = Thread.new do
  read_io.read
end
Thread.pass until thread.stop?
read_io.close
write_io.close
thread.join

Ruby 2.4.0

io_ruby.rb:3:in `read': stream closed (IOError)
        from io_ruby.rb:3:in `block in <main>'

Ruby 2.5.0

#<Thread:[email protected]_ruby.rb:2 run> terminated with exception (report_on_exception is true):
Traceback (most recent call last):
        1: from io_ruby.rb:3:in `block in <main>'
io_ruby.rb:3:in `read': stream closed in another thread (IOError)
Traceback (most recent call last):
        1: from io_ruby.rb:3:in `block in <main>'
io_ruby.rb:3:in `read': stream closed in another thread (IOError)

There you go. We got our error message “stream closed in another thread”

Comments

comments powered by Disqus