Ruby同步:如何使线程以正确的顺序一个接一个地工作? [英] Ruby synchronisation: How to make threads work one after another in proper order?
问题描述
我的问题是我不知道如何使用Ruby同步多个线程.该任务是创建六个线程并立即启动它们.他们都应该按我需要的顺序依次进行一些工作(例如puts "Thread 1" Hi"
).
My problem is that I don't know how synchronise multiple threads using Ruby. The task is to create six threads and start them immediately. All of them should do some work (for example puts "Thread 1" Hi"
) one after another in the order I need it to work.
经过一段时间与Mutex和Condition Variable的斗争之后,我实现了我的目标. 这段代码有点混乱,我故意不使用循环来获得更清晰的视图".
After some time of struggling with Mutex and Condition Variable I've achieved my goal. This code is a little bit messy, and I intentionally did't use cycles for "clearer view".
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信号量
您可以使用以下方法滥用队列就像传统的 PV信号.为此,您创建一个Queue实例:
Using Queue as a PV Semaphore
You can abuse Queue, using it like a traditional PV Semaphore. To do this, you create an instance of Queue:
require 'thread'
...
sem = Queue.new
当线程需要等待时,它调用队列#deq :
When a thread needs to wait, it calls Queue#deq:
# waiting thread
sem.deq
当其他某个线程想要取消阻塞正在等待的线程时,它将某些东西(任何东西)推入队列:
When some other thread wants to unblock the waiting thread, it pushes something (anything) onto the queue:
# another thread that wants to unblock the waiting thread
sem.enq :go
工人阶级
这是一个使用Queue同步其开始和结束的工作程序类:
A Worker class
Here's a worker class that uses Queue to synchronize its start and stop:
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 constructed, a worker creates a thread, but that thread then waits on the @start
queue. Not until #start is called will the thread unblock.
完成后,线程将执行被#when_done调用的块.稍后,我们将看到如何使用它.
When done, the thread will execute the block that was called to #when_done. We'll see how this is used in just a moment.
首先,让我们确保如果有任何线程引发异常,我们将对其进行查找:
First, let's make sure that if any threads raise an exception, we get to find out about it:
Thread.abort_on_exception = true
我们需要六个工人:
workers = (1..6).map { |i| Worker.new(i) }
告诉每个工人完成后该怎么做
这是#when_done起作用的地方:
Telling each worker what to do when it's done
Here's where #when_done comes into play:
workers.each_cons(2) do |w1, w2|
w1.when_done { w2.start }
end
这将轮流每对工人.每个工作人员(最后一个工作人员除外)都被告知,完成工作后,应在工作人员之后启动工作人员.剩下的只有最后一个工人.完成后,我们希望它通知该线程:
This takes each pair of workers in turn. Each worker except the last is told, that when it finishes, it should start the worker after it. That just leaves the last worker. When it finishes, we want it to notify this thread:
all_done = Queue.new
workers.last.when_done { all_done.enq :done }
走吧!
现在剩下的就是启动第一个线程:
Let's Go!
Now all that remains is to start the first thread:
workers.first.start
并等待最后一个线程完成:
and wait for the last thread to finish:
all_done.deq
输出:
Thread 1
Thread 2
Thread 3
Thread 4
Thread 5
Thread 6
这篇关于Ruby同步:如何使线程以正确的顺序一个接一个地工作?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!