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

标签 ruby multithreading mutex

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

相关文章:

c++ - 将 pthread_mutex_t obj 嵌入到 C++ obj 实例中是个好主意吗?我认为(可悲的是)没有 bat

javascript - 无法使用 Watir 从特定网页抓取数据

c - 是否可以确定持有互斥体的线程?

multithreading - 如何从Erlang中的now()获得微秒

c++ - c++20 中的 std::jthread 是什么?

c++ - boost::threads 执行顺序

c - 使用互斥体设置 pthread 的优先级

ruby - 当猴子修补实例方法时,您可以从新实现中调用覆盖的方法吗?

ruby-on-rails - ruby 和 ruby​​ on rails 一书 (2009)

ruby-on-rails - 如何获取八达通分片的数据库连接?