【问题标题】:How to execute threads in order in Ruby如何在Ruby中按顺序执行线程
【发布时间】:2021-11-15 19:50:34
【问题描述】:

我有一个作业,我有 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 threads left. Deadlock? (fatal)

这种方法可行吗?我应该怎么做才能修复它?还有其他更好的方法吗?

【问题讨论】:

    标签: ruby multithreading mutex


    【解决方案1】:

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

    当线程 A“通知/发出信号”一个条件变量时,它会“唤醒”已经在等待的其他线程,但如果此时没有其他线程发生在等待,则发出信号/notification 什么都不做。

    条件变量不记住通知。

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

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

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

    t1 线程从sleep(3) 返回,它向条件变量发出信号。但是,条件变量不记得通知。其他线程都无法到达它们的wait(mutex) 调用,因为它们都仍在尝试通过mutex.synchronize。通知丢失。

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

    同时,主线程一直挂在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()
    

    【讨论】:

    • 我想我现在更好地理解了这个问题。我创建了this 以查看是否可以让线程按顺序运行并且它在大多数情况下都可以正常工作,但是我时不时会遇到一些死锁错误。这可能是什么原因?
    • 是的,看起来更好。
    • 我用广播替换了信号,现在它似乎工作正常。你能确认这是正确的吗?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2016-05-17
    • 1970-01-01
    • 1970-01-01
    • 2018-05-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多