我有一个作业,其中有 2 个数字(a 和 b)和一个计数 (n)。我需要首先生成随机数,这将是每个线程休眠的时间。然后,每个线程分别计算 a 和 b 的和、差、乘积和除法,并重复 n 次。例如:
a = 10
b = 2
n = 2
SUM: 12
DIFFERENCE: 8
PRODUCT: 20
DIVISION: 5
SUM: 12
DIFFERENCE: 8
PRODUCT: 20
DIVISION: 5
在每一行之间,程序会休眠几秒钟。顺序必须是和、差、乘积和除法。我不能重复使用队列或终止/生成线程。我的第一个想法是使用 4 个条件变量来规定线程需要运行的顺序。我想出了这个:
mutex = Mutex.new
resources = Array.new(4) { ConditionVariable.new }
t1 = Thread.new do
mutex.synchronize do
puts "Thread 1"
sleep(3)
resources[0].signal
end
end
t2 = Thread.new do
mutex.synchronize do
resources[0].wait(mutex)
puts "Thread 2"
sleep(3)
resources[1].signal
end
end
t3 = Thread.new do
mutex.synchronize do
resources[1].wait(mutex)
puts "Thread 3"
sleep(3)
resources[2].signal
end
end
t4 = Thread.new do
mutex.synchronize do
resources[2].wait(mutex)
puts "Thread 4"
sleep(3)
end
end
t1.join
t2.join
t3.join
t4.join
但我收到此死锁错误:main.rb:39:in 'join': No live thread left。僵局? (致命)
这个方法可行吗?我应该做什么来修复它?还有其他更好的方法可以工作吗?
最佳答案
我不是 Ruby 专家,但在我使用过的所有其他语言中,“条件变量”这个名称是用词不当。对于任何其他称为“变量”的东西,我们希望如果一个线程更改它,其他线程稍后可以看到它已更改。这不是条件变量的工作原理。
当线程 A“通知/发出信号”条件变量时,它将“唤醒”已经在等待的某个其他线程,但如果此时没有其他线程发生等待,则信号/notification 根本不做任何事情。
条件变量不记住通知。
我认为可能会发生以下情况:
t1
线程锁定互斥锁,然后休眠。
其他三个线程都启动,并且在等待互斥体时都被阻塞。
t1
线程从 sleep(3)
返回,并向条件变量发出信号。但是,条件变量不记得通知。其他线程都无法获取其 wait(mutex)
调用,因为它们仍在尝试获取过去的mutex.synchronize
。通知丢失。
t1
线程离开同步块(synchronized block),其他线程一一进入其同步块(synchronized block),直到所有线程都在等待信号。
与此同时,主线程一直卡在t1.join()
中。该调用在 t1
线程结束时返回,但随后主线程调用 t2.join()
t2
正在等待信号, t3
正在等待信号,t4
正在等待信号,主线程正在等待 t2
终止。
不再有事件线程。
再说一遍,我不是 ruby 专家,但在所有其他语言中,使用条件变量等待某些“条件”的线程必须执行如下操作:
# The mutex prevents other threads from modifying the "condition"
# (i.e., prevents them from modifying the `sharedData`.)
mutex.lock()
while ( sharedData.doesNotSatisfyTheCondition() ) {
# The `wait()` call _temporarily_ unlocks the mutex so that other
# threads may make the condition become true, but it's _guaranteed_
# to re-lock the mutex before it returns.
conditionVar.wait(mutex)
}
# At this point, the condition is _guaranteed_ to be true.
sharedData.doSomethingThatRequiresTheConditionToBeTrue()
mutex.unlock()
这里发生的最重要的事情是,如果条件已经为真,调用者不会等待。如果条件已经为真,则通知可能已经发生。我们错过了,如果现在等待,我们可能会永远等待。
另一件重要的事情是,在我们等待并收到通知后,我们会再次检查情况。取决于编程语言的规则、操作系统和程序的架构; wait()
可能可能会提前返回。
使条件成立很简单:
mutex.lock()
sharedData.doSomethingThatMakesTheConditionTrue()
conditionVar.notify()
mutex.unlock()
关于ruby - 如何在Ruby中按顺序执行线程,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/69980072/