Sp4ce.net
Mutex global en Ruby
Quand différents processus nécessitent d'éxécuter une section critique, certains languages haut niveau proposent des mutex globaux, mais cela n'existe pas en Ruby.
Mutex Global
Dans un environnement multi thread, si vous voulez protéger une section critique, vous pouvez utiliser des sémaphores. Cependant en Ruby, le sémaphore is uniquement instancié dans le processsus courant et ne peut pas être partagé avec d’autres processus ruby.
Imaginez maintenant que vous avez un code ruby qui est exécuté par une application extern. Ce code contient une section critique et vous voulez la protéger.
chech.rb
puts "take lock"
# to be defined
puts "begin critical section"
sleep 2
puts "end critical section"
puts "release lock"
Ensuite, pour simuler les appels de l’application externe, nous avons un petit batch loop.bat
qui appelle le code Ruby quatre fois.
loop.bat
for /L %%i in (0, 1, 3) do start ruby check.rb %%i
Méthode File.flock
Pour résoudre cela, la méthode File.flock
permet de prendre une ressource exclusive sur un fichier. Donc check.rb
devient :
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
Ensuite, quand vous exécutez loop.bat
vous avez un mutex global, cela veut dire que chaque processus attend que les autres processus relâchent le verrou sur le fichier test.synchro
. Le fichier est dans un répertoire TEMP
pour être sûr d’avoir les accès en écriture sur ce répertoire. Cela sera /temp
sur linux, c:\users\UTILISATEUR_COURANT\app_data\temp
sur MS Windows. Je n’ai pas essayé sur mon Mac, mais je pense que chaque appel à Dit.tmpdir
renvoie le même répertoire.
Demo
Voici une capture d’écran quand ce petit bout de code toutne (cliquez pour agrandir). Examinez les horodatages de chaque action (plus spécifiquement les sécondes) pour comprendre ce qui se passe.