ConditionVariable 对象增强了 Mutex. 使用 条件变量 , 可以在 “锁区”(in the middle of a critical section) 挂起直到资源可用.

mutex = Mutex.new
resource = ConditionVariable.new

c1 = Thread.new {
  mutex.synchronize {
    puts "c1 start"
    resource.wait(mutex) # 等待 resource 到位才能继续, 否则阻塞
    puts "c1 end"
  }
}

sleep 0.5 # 确保线程启动顺序

c2 = Thread.new {
  mutex.synchronize {
    puts "c2 start"
    resource.wait(mutex, 10) # 最多阻塞 10s, 即使没有信号通知也返回. (超时不影响锁的竞争)
    puts "c2 end"
  }
}

sleep 0.5 # 确保线程启动顺序

p1 = Thread.new {
  mutex.synchronize {
    puts "p1 start; p1 need sleep:"
    3.times do
      print "."
      sleep 1
    end
    resource.signal # 给等待的resource资源的第一个线程(c1)发信号, 通知资源其到位了: 将其唤醒
    # resource.broadcast # 给等待的resource资源的所有线程(c1和c2)广播信号: 将他们唤醒
    puts "p1 end"
  }
}

c1.join
c2.join
p1.join

puts "main end"


=begin

c1 start
c2 start
p1 start; p1 need sleep:
...p1 end
c1 end 
c2 end # 这里等了大约7秒
main end

=end

wait

释放 Mutex 锁, 并等待资源就位; 当唤醒线程的时候重新获得锁.

如果设置了超时, 则超时后方法返回, 即使没有其他线程通知它资源就位(在获得mutex锁的前提下).

特别注意

resource.wait(mutex) 必须包装在 mutex.synchronize 的 block 内使用, 因为唤醒该线程的前提是获得锁.

如果等待信号的线程(比如c1或c2)join时并没有其他活跃线程, 会报致命死锁:

No live threads left. Deadlock? (fatal)