mirror of
https://github.com/ruby/ruby.git
synced 2022-11-09 12:17:21 -05:00
739fdb7ff0
RDoc says nothing about them. Added an example that ConditionVariable#wait can be woken up by ConditionVariable#signal, instead.
177 lines
3.9 KiB
Ruby
177 lines
3.9 KiB
Ruby
require_relative '../../spec_helper'
|
|
require 'thread'
|
|
|
|
describe "ConditionVariable#wait" do
|
|
it "calls #sleep on the given object" do
|
|
o = Object.new
|
|
o.should_receive(:sleep).with(1234)
|
|
|
|
cv = ConditionVariable.new
|
|
|
|
cv.wait(o, 1234)
|
|
end
|
|
|
|
it "can be woken up by ConditionVariable#signal" do
|
|
m = Mutex.new
|
|
cv = ConditionVariable.new
|
|
in_synchronize = false
|
|
|
|
th = Thread.new do
|
|
m.synchronize do
|
|
in_synchronize = true
|
|
cv.wait(m)
|
|
end
|
|
:success
|
|
end
|
|
|
|
# wait for m to acquire the mutex
|
|
Thread.pass until in_synchronize
|
|
# wait until th is sleeping (ie waiting)
|
|
Thread.pass until th.stop?
|
|
|
|
m.synchronize { cv.signal }
|
|
th.value.should == :success
|
|
end
|
|
|
|
it "can be interrupted by Thread#run" do
|
|
m = Mutex.new
|
|
cv = ConditionVariable.new
|
|
in_synchronize = false
|
|
|
|
th = Thread.new do
|
|
m.synchronize do
|
|
in_synchronize = true
|
|
cv.wait(m)
|
|
end
|
|
:success
|
|
end
|
|
|
|
# wait for m to acquire the mutex
|
|
Thread.pass until in_synchronize
|
|
# wait until th is sleeping (ie waiting)
|
|
Thread.pass until th.stop?
|
|
|
|
th.run
|
|
th.value.should == :success
|
|
end
|
|
|
|
it "can be interrupted by Thread#wakeup" do
|
|
m = Mutex.new
|
|
cv = ConditionVariable.new
|
|
in_synchronize = false
|
|
|
|
th = Thread.new do
|
|
m.synchronize do
|
|
in_synchronize = true
|
|
cv.wait(m)
|
|
end
|
|
:success
|
|
end
|
|
|
|
# wait for m to acquire the mutex
|
|
Thread.pass until in_synchronize
|
|
# wait until th is sleeping (ie waiting)
|
|
Thread.pass until th.stop?
|
|
|
|
th.wakeup
|
|
th.value.should == :success
|
|
end
|
|
|
|
it "reacquires the lock even if the thread is killed" do
|
|
m = Mutex.new
|
|
cv = ConditionVariable.new
|
|
in_synchronize = false
|
|
owned = nil
|
|
|
|
th = Thread.new do
|
|
m.synchronize do
|
|
in_synchronize = true
|
|
begin
|
|
cv.wait(m)
|
|
ensure
|
|
owned = m.owned?
|
|
$stderr.puts "\nThe Thread doesn't own the Mutex!" unless owned
|
|
end
|
|
end
|
|
end
|
|
|
|
# wait for m to acquire the mutex
|
|
Thread.pass until in_synchronize
|
|
# wait until th is sleeping (ie waiting)
|
|
Thread.pass until th.stop?
|
|
|
|
th.kill
|
|
th.join
|
|
|
|
owned.should == true
|
|
end
|
|
|
|
ruby_bug '#14999', ''...'2.5' do
|
|
it "reacquires the lock even if the thread is killed after being signaled" do
|
|
m = Mutex.new
|
|
cv = ConditionVariable.new
|
|
in_synchronize = false
|
|
owned = nil
|
|
|
|
th = Thread.new do
|
|
m.synchronize do
|
|
in_synchronize = true
|
|
begin
|
|
cv.wait(m)
|
|
ensure
|
|
owned = m.owned?
|
|
$stderr.puts "\nThe Thread doesn't own the Mutex!" unless owned
|
|
end
|
|
end
|
|
end
|
|
|
|
# wait for m to acquire the mutex
|
|
Thread.pass until in_synchronize
|
|
# wait until th is sleeping (ie waiting)
|
|
Thread.pass until th.stop?
|
|
|
|
m.synchronize {
|
|
cv.signal
|
|
# Wait that the thread is blocked on acquiring the Mutex
|
|
sleep 0.001
|
|
# Kill the thread, yet the thread should first acquire the Mutex before going on
|
|
th.kill
|
|
}
|
|
|
|
th.join
|
|
owned.should == true
|
|
end
|
|
end
|
|
|
|
it "supports multiple Threads waiting on the same ConditionVariable and Mutex" do
|
|
m = Mutex.new
|
|
cv = ConditionVariable.new
|
|
n_threads = 4
|
|
events = []
|
|
|
|
threads = n_threads.times.map {
|
|
Thread.new {
|
|
m.synchronize {
|
|
events << :t_in_synchronize
|
|
cv.wait(m)
|
|
}
|
|
}
|
|
}
|
|
|
|
Thread.pass until m.synchronize { events.size } == n_threads
|
|
Thread.pass until threads.any?(&:stop?)
|
|
m.synchronize do
|
|
threads.each { |t|
|
|
# Cause interactions with the waiting threads.
|
|
# On TruffleRuby, this causes a safepoint which has interesting
|
|
# interactions with the ConditionVariable.
|
|
bt = t.backtrace
|
|
bt.should be_kind_of(Array)
|
|
bt.size.should >= 2
|
|
}
|
|
end
|
|
|
|
cv.broadcast
|
|
threads.each(&:join)
|
|
end
|
|
end
|