Search code examples
jruby

Writing to a file from multiple threads


I am trying to write out to a text file using multiple threads, however the code below gives me an exception - IOError: closed stream

threads = []
File.open("test.txt", "a") do |fp|
  500.times do |time|
    threads << Thread.new do
      fp.puts("#{time}: 1")
      sleep(rand(100) / 100.0)
      fp.puts("#{time}: 2")
    end
  end
end

threads.each{ |thread| thread.join }

Solution

  • Move the join inside the file.open block:

    threads = []
    File.open("test.txt", "a") do |fp|
      500.times do |time|
        threads << Thread.new do
          fp.puts("#{time}: 1")
          sleep(rand(100) / 100.0)
          fp.puts("#{time}: 2")
        end
      end
    
      threads.each{ |thread| thread.join }
    end
    
    

    Why? Thread.new launches the thread, but it runs in parallel, and the life of the thread in your version isn't guaranteed to be shorter than the life of the file. File.open closes the file after you exit the attached block. By waiting to close the file until after all the threads are done, everything will work as expected.

    However, please note that this IS NOT thread safe on JRuby (or any other implementation without a GIL) and may have output intermixed:

    6: 1
    5: 17: 1
    8: 1
    
    3: 10: 110: 1
    4: 11: 1
    2: 19: 1
    
    11: 1
    
    
    
    12: 1
    13: 1
    14: 1
    
    

    Note: this question appears to be from Ruby MRI 1.8.7 - File writing thread safety