gpt4 book ai didi

ruby 同步 : How to make threads work one after another in proper order?

转载 作者:数据小太阳 更新时间:2023-10-29 07:49:55 25 4
gpt4 key购买 nike

我的问题是我不知道如何使用 Ruby 同步多个线程。任务是创建六个线程并立即启动它们。它们都应该按照我需要它工作的顺序一个接一个地做一些工作(例如 puts "Thread 1"Hi")。

我曾尝试使用 Mutex、Monitor 和 Condition Variable,但它们都以随机顺序工作。谁能解释一下如何实现我的目标?

经过一段时间与 Mutex 和 Condition Variable 的斗争之后,我实现了我的目标。这段代码有点乱,我故意没有使用循环来“看得更清楚”。

cv = ConditionVariable.new
mutex = Mutex.new

mutex2 = Mutex.new
cv2 = ConditionVariable.new

mutex3 = Mutex.new
cv3 = ConditionVariable.new

mutex4 = Mutex.new
cv4 = ConditionVariable.new

mutex5 = Mutex.new
cv5 = ConditionVariable.new

mutex6 = Mutex.new
cv6 = ConditionVariable.new



Thread.new do
mutex.synchronize {
puts 'First: Hi'
cv.wait(mutex)
puts 'First: Bye'
#cv.wait(mutex)
cv.signal
puts 'First: One more time'
}

end

Thread.new do
mutex.synchronize {
puts 'Second: Hi'
cv.signal
cv.wait(mutex)
puts 'Second:Bye'
cv.signal
}

mutex2.synchronize {
puts 'Second: Starting third'
cv2.signal

}
end

Thread.new do
mutex2.synchronize {
cv2.wait(mutex2)
puts 'Third: Hi'
}

mutex3.synchronize {
puts 'Third: Starting forth'
cv3.signal
}
end

Thread.new do
mutex3.synchronize {
cv3.wait(mutex3)
puts 'Forth: Hi'
}

mutex4.synchronize {
puts 'Forth: Starting fifth'
cv4.signal
}
end

Thread.new do
mutex4.synchronize {
cv4.wait(mutex4)
puts 'Fifth: Hi'
}

mutex5.synchronize {
puts 'Fifth: Starting sixth'
cv5.signal
}
end

Thread.new {
mutex5.synchronize {
cv5.wait(mutex5)
puts 'Sixth:Hi'
}
}

sleep 2

最佳答案

使用队列作为 PV 信号量

你可以滥用Queue ,像传统的一样使用它 PV Semaphore .为此,您创建一个 Queue 实例:

require 'thread'
...
sem = Queue.new

当一个线程需要等待时,它调用Queue#deq :

# waiting thread
sem.deq

当其他线程想要解除阻塞等待线程时,它会将某些东西(任何东西)推到队列中:

# another thread that wants to unblock the waiting thread
sem.enq :go

worker 类

这是一个使用 Queue 来同步其开始和停止的工作类:

class Worker

def initialize(worker_number)
@start = Queue.new
Thread.new do
@start.deq
puts "Thread #{worker_number}"
@when_done.call
end
end

def start
@start.enq :start
end

def when_done(&block)
@when_done = block
end

end

构造时,一个工作线程创建一个线程,但该线程然后在 @start 队列上等待。直到调用#start,线程才会解除阻塞。

完成后,线程将执行调用#when_done 的 block 。稍后我们将看到如何使用它。

创建 worker

首先,让我们确保如果有任何线程引发异常,我们会发现它:

Thread.abort_on_exception = true

我们需要六个 worker :

workers = (1..6).map { |i| Worker.new(i) }

告诉每个 worker 完成后该做什么

这里是#when_done 发挥作用的地方:

workers.each_cons(2) do |w1, w2|
w1.when_done { w2.start }
end

这需要每对 worker 轮流进行。每个 worker 除了最后一个被告知,当它完成时,它应该在它之后启动 worker 。那只剩下最后一个 worker 了。当它完成时,我们希望它通知这个线程:

all_done = Queue.new
workers.last.when_done { all_done.enq :done }

我们走吧!

现在剩下的就是启动第一个线程:

workers.first.start

并等待最后一个线程完成:

all_done.deq

输出:

Thread 1
Thread 2
Thread 3
Thread 4
Thread 5
Thread 6

关于 ruby 同步 : How to make threads work one after another in proper order?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/23766882/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com