如何在 Ruby 中按顺序执行线程

How to execute threads in order in Ruby

我有一个作业,其中有 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

在每一行之间,程序会休眠几秒钟。顺序必须是和、差、积和除法。我不能重复使用队列或 kill/spawn 线程。我的第一个想法是使用 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 threads left. Deadlock? (fatal)

这种方法行得通吗?我应该怎么做才能解决它?还有其他更好的方法吗?

我不是 ruby 专家,但在我使用过的所有其他语言中,名称“条件 变量”是用词不当。对于任何其他称为“变量”的东西,我们希望如果一个线程更改它,其他线程可以稍后出现并看到它已更改。那是不是条件变量的工作方式。

当线程A“notifies/signals”一个条件变量时,它将“唤醒”其他已经在等待的线程,但是如果没有其他线程发生等待在那一刻,signal/notification 什么都不做。

条件变量记住通知。

这是我认为可能发生的情况:

t1 线程锁定互斥量,然后休眠。

其他三个线程全部启动,都在等待互斥体时被阻塞。

来自 sleep(3)t1 线程 return,它向条件变量发出信号。但是,条件变量不记得通知。其他线程的 None 已经能够进行它们的 wait(mutex) 调用,因为它们都还在尝试通过 mutex.synchronize。通知已丢失。

t1 线程离开同步块,其他线程一个接一个地进入它们的同步块,直到所有线程都在等待信号。

同时,主线程一直挂在t1.join()。即在t1线程结束时调用returns,但随后主线程调用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() 到 return 过早。


使条件变为真很简单:

mutex.lock()
sharedData.doSomethingThatMakesTheConditionTrue()
conditionVar.notify()
mutex.unlock()