English Version

Sp4ce.net rss

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.

ruby_global_mutex ruby_global_mutex