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.