Ruby中如何使用条件变量按固定顺序执行线程并解决死锁问题
思路可行性与死锁原因
用条件变量控制执行顺序的思路是可行的,你遇到死锁的核心原因有两个:
- 所有线程的逻辑仅能执行一次,执行完成后线程直接退出,没有实现重复执行n次的循环逻辑,主进程调用join时所有子线程已经终止,就会触发死锁报错。
- 你把休眠逻辑放在了锁的临界区内,导致四个线程全程串行持有锁,完全没有释放锁的空隙,也不符合“计算完成后休眠”的需求。
修复实现方案
我们通过引入全局状态标记当前要执行的任务步骤、在每个线程内增加循环逻辑、将休眠移到临界区外解决问题,修复后代码如下:
a = 10 b = 2 n = 2 # 预先生成每个线程对应的随机休眠时长,单位可根据需求调整 sleep_times = Array.new(4) { rand(0.1..1.0) } mutex = Mutex.new cond = ConditionVariable.new # current_step标记当前应执行的任务:0=求和、1=求差、2=求积、3=求商 current_step = 0 # 求和线程 t_sum = Thread.new do n.times do mutex.synchronize do # 非当前执行步骤则等待 while current_step != 0 cond.wait(mutex) end puts "SUM: #{a + b}" current_step = 1 cond.broadcast end # 计算完成后再休眠,休眠逻辑放在锁外避免阻塞其他线程 sleep sleep_times[0] end end # 求差线程 t_diff = Thread.new do n.times do mutex.synchronize do while current_step != 1 cond.wait(mutex) end puts "DIFFERENCE: #{a - b}" current_step = 2 cond.broadcast end sleep sleep_times[1] end end # 求积线程 t_product = Thread.new do n.times do mutex.synchronize do while current_step != 2 cond.wait(mutex) end puts "PRODUCT: #{a * b}" current_step = 3 cond.broadcast end sleep sleep_times[2] end end # 求商线程 t_div = Thread.new do n.times do |round_idx| mutex.synchronize do while current_step != 3 cond.wait(mutex) end puts "DIVISION: #{a / b}" # 非最后一轮输出空行分隔 puts "" if round_idx != n - 1 current_step = 0 cond.broadcast end sleep sleep_times[3] end end # 等待所有线程执行完成 t_sum.join t_diff.join t_product.join t_div.join
运行上述代码即可输出和示例完全一致的结果,且符合仅创建一次线程、不使用队列的限制要求。
优化建议
- 可将四个线程的公共调度逻辑抽离,用数组存储对应的计算函数,减少重复代码,方便后续扩展其他计算逻辑。
- 商的计算逻辑可增加除数为0的异常处理,避免b为0时程序崩溃。
内容的提问来源于stack exchange,提问作者KleberPF
相关产品推荐
相关产品推荐

