B
Brian Schroeder
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
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 ===
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
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 ===