I also could not create a mistake.
You are probably working with file locking. If you want multiple threads to be written to the same file, all of them must use the same file object:
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 }
In this example, the GIL will likely save you from any real thread errors, but I'm not sure what will happen in JRuby, which uses real threads, and two entries can happen at the same time. The same goes for other real-thread Ruby engines.
Regarding the issue of wherever you protect your code with locks, it comes down to the fact that if you want to rely on the Ruby engine you use, you must save money or want to encode a solution that "should" work on all Ruby- engine, regardless of whether they have built-in functions, to save you from concurrency problems.
Another question: if your operating system and / or file system saves you from stream errors with file locks, and if your code should be independent of the operating system and / or file system, it means that you are not dependent on file system locks, to ensure that your file openings and records are correctly synchronized by the operating system and / or file system.
I will go to the limb and say that it seems good practice that you also implement locks on your side to make sure your code works no matter which Ruby engine, operating system or file system someone else uses your code although most modern Ruby engines, operating systems, and file systems have built-in features.
source share