I have method a
that is invoked repeatedly at some random time, which triggers method b
, which is completely executed after some random time and is in it own thread. I want to ensure that a subsequent execution of a
waits until b
is completed, which is triggered by the current execution of a
. In other words, a
and b
are to be executed alternatively. I tried to do this using mutex and condition variable as follows:
def a
Thread.new do
$mutex.synchronize do
puts "a"
b
$cv.wait($mutex)
end
end
end
def b
Thread.new do
sleep(rand)
$mutex.synchronize do
puts "b"
$cv.signal
end
end
end
$mutex, $cv = Mutex.new, ConditionVariable.new
loop{a; sleep(rand)}
In this code, $mutex.synchronize do ... end
in method a
ensures that $cv.signal
(also within another $mutex.synchronize do ... end
) in method b
is not invoked until $cv.wait($mutex)
sets $cv
into listening mode for signals. This much is given in the document.
Another function I intended to assign to $mutex.synchronize do ... end
in method a
is to avoid consecutive execution of method a
. My reasoning is that $cv.wait($mutex)
in method a
should avoid $mutex
from being completed and released until $cv.signal
in method b
is invoked, by which time b
should be finished.
I expected that a
and b
are executed alternatively, thereby printing "a"
and "b"
alternatively. But in reality, they are not; each of "a"
or "b"
can be printed consecutively.
After that, I thought that my reasoning above may be wrong in the sense that $mutex
is rather completed and released even if $cv
(or $mutex
) is in waiting mode, once $cv.wait($mutex)
has been called. So I added some dummy process to a
, changing it to:
def a
Thread.new do
$mutex.synchronize do
puts "a"
b
$cv.wait($mutex)
nil # Dummy process intended to keep `$mutex` locked until `$cv` is released
end
end
end
but that did not have effect.
How can this be fixed? Or, what am I wrong about this?