On Jul 25, 2004, at 2:06 PM, Brian Schroeder wrote: > Hello, > > playing around with threads I observed, that it is impossible to lock a > mutex twice from within the same thread. Coming from a delphi > background Look at monitor.rb (comes in standard Ruby distribution). It has almost same API as Mutex, however it was designed to be re-enterable by the current owner. > I'm used to have the possibility to enter a critical section as often > as I > like, as long as I'm in the same thread. That allows for some simpler > programming, as I can for example allow the user to read from a > protected > accessor while he has aquired the lock for some bigger operation. > > To be more specific: > > The following is not working: > === Test 1 === > require 'thread' > > m = Mutex.new > > m.synchronize do > puts 'locked level 1' > m.synchronize do > puts 'level 2' > end > end > === EOF === > > I'd like to use it for this usecase: > > === usecase === > class A > def initialize > @lock = Mutex.new > end > > def x > result = '' > @lock.synchronize do > # Do something with result > end > result > end > > def synchronize > @lock.synchronize do yield end > end > end > > a = A.new > a.synchronize do > # Do something with a > puts a.x > # Do some more with a > end > === EOF === > > I looked into the thread library and came up with some changes that > should > implement the behaviour I want. But my knowledge of ruby threads is > quite > limited, so I'd like your feedback on how good this is. Also I'm > interested if you think that this is a good idea, and if it should be > proposed for inclusion in the standard library? > > === MultiMutex === > class MultiMutex < Mutex > def initialize > @lockingthread = nil > @lockdepth = 0 > super > end > > def lock > Thread.critical = true > begin > if @lockingthread = Thread.current then > @lockdepth += 1 > else > while (Thread.critical = true; @lockdepth > 0) > @waiting.push Thread.current > Thread.stop > end > @lockdepth = 1 > end > ensure > Thread.critical = false > end > self > end > > def unlock > return @lockdepth unless @locked > Thread.critical = true > begin > if @lockdepth > 1 then > @lockdepth -= 1 > return @lockdepth > else > @lockingthread = nil > @lockdepth = 0 > begin > t = @waiting.shift > t.wakeup if t > rescue ThreadError > retry > end > end > ensure > Thread.critical = false > end > begin > t.run if t > rescue ThreadError > end > @lockdepth > end > end > === EOF === > > -- > Brian Schröäer > http://www.brian-schroeder.de/ > > Sincerely, Gennady Bystritsky