Sp4ce.net
Global mutex in Ruby
When different processes require to run a critical section, some high level language provides global mutexes, but they don't exist in Ruby.
Global Mutex
In a multi thread environment, if you want to protect a critical section, you can use a semaphore. However in Ruby, this semaphore is only intantiated in your current process and cannot be shared among other ruby processes.
Imagine that you have a ruby code that is run by an external application. This code contains a critical section and you want to protect it.
chech.rb
puts "take lock"
# to be defined
puts "begin critical section"
sleep 2
puts "end critical section"
puts "release lock"
Then to simulate the external application calls, we have a small batch script loop.bat
that calls the Ruby code four times.
loop.bat
for /L %%i in (0, 1, 3) do start ruby check.rb %%i
File.flock method
To solve this, the method File.flock
allows you take an exclusive ressource on a file. So check.rb
looks like:
chech.rb
require 'fileutils.rb'
require 'tmpdir'
File.open("#{Dir.tmpdir}/test.synchro", 'w') { |f|
puts "take lock #{ARGV[0]}"
f.flock(File::LOCK_EX)
puts "sleep #{ARGV[0]}"
sleep 2
puts "end #{ARGV[0]}"
}
sleep 60
Then when you run loop.bat
you have a global mutex, meaning that each process wait that every other process release the lock on the file test.synchro
. The file is in the TEMP
directory to be sure that you can have write access on this folder. It will be /temp
on linux and c:\users\CURRENT_USER\app_data\temp
on MS Windows. I didn’t try on my Mac, but I think that each call to Dir.tmpdir
return the same folder.
Demo
Here a screenshot of when this short code runs (click to enlarge). You have to look closely to the timestamp of each action (specially the seconds) to understand what is happenning.