From: John Carter Date: 2008-10-06T11:11:26+09:00 Subject: Ruby lacks atfork : The evil that lives in fork... --Boundary_(ID_IVf9GjaWysXJE0eBU6oNcA) Content-type: TEXT/PLAIN; charset=UTF-8; format=flowed Content-transfer-encoding: QUOTED-PRINTABLE Consider this simple usage of Thread and Process.... I use a mutex to block access to the $state variable when it is in an "inconsistent" state. =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D require 'thread' require 'pp' Thread.abort_on_exception =3D true $state =3D "Uninited" def state(m) print "#{caller(0)[1]}: #{Time.now} #{$state} " if m.locked? puts "Mutex locked" else puts "Mutex unlocked" end end m =3D Mutex.new state(m) $state =3D "Good" t =3D Thread.new do begin state(m) m.synchronize do $state =3D "Inconsistent" state(m) sleep 10 $state =3D "Good Again" state(m) end ensure state(m) end end state(m) sleep 2 state(m) pid =3D Process.fork do state(m) sleep 2 state(m) end state(m) pp Process.waitpid2(pid) t.join state(m) =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D This is what it outputs... ruby -v;ruby -w evil_fork.rb ruby 1.8.7 (2008-06-20 patchlevel 22) [i686-linux] evil_fork.rb:16: Mon Oct 06 14:51:17 +1300 2008 Uninited Mutex unlock= ed evil_fork.rb:20: Mon Oct 06 14:51:17 +1300 2008 Good Mutex unlocked evil_fork.rb:23: Mon Oct 06 14:51:17 +1300 2008 Inconsistent Mutex lo= cked evil_fork.rb:33: Mon Oct 06 14:51:17 +1300 2008 Inconsistent Mutex lo= cked evil_fork.rb:36: Mon Oct 06 14:51:19 +1300 2008 Inconsistent Mutex lo= cked evil_fork.rb:39: Mon Oct 06 14:51:19 +1300 2008 Inconsistent Mutex un= locked evil_fork.rb:46: Mon Oct 06 14:51:19 +1300 2008 Inconsistent Mutex lo= cked evil_fork.rb:43: Mon Oct 06 14:51:21 +1300 2008 Inconsistent Mutex un= locked [5082, #] evil_fork.rb:26: Mon Oct 06 14:51:27 +1300 2008 Good Again Mutex lock= ed evil_fork.rb:29: Mon Oct 06 14:51:27 +1300 2008 Good Again Mutex unlo= cked evil_fork.rb:51: Mon Oct 06 14:51:27 +1300 2008 Good Again Mutex unlo= cked =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D Oh dear! When I Process.fork'ed I saw this.... evil_fork.rb:39: Mon Oct 06 14:51:19 +1300 2008 Inconsistent Mutex un= locked ie. I could be accessing $state when it is in an inconsistent state and the Mutex doesn't protect me. =46rom the fork man page... * The child process is created with a single thread =E2=80= =94 the one that called fork(). The entire virtual address space of the parent is replicated in the child, including the states of mutexes, condition variables, and other pthreads objects= ; the use of pthread_atfork(3) may be helpful for dealing wit= h problems that this can cause. Unfortunately Ruby doesn't provide an atfork facility. John Carter Phone : (64)(3) 358 6639 Tait Electronics Fax : (64)(3) 359 4632 PO Box 1645 Christchurch Email : john.carter@tait.co.n= z New Zealand --Boundary_(ID_IVf9GjaWysXJE0eBU6oNcA)--