我需要有一个线程来阻止自己然后被另一个线程唤醒。我遇到的问题是我无法找到一个完全万无一失的好解决方案。我现在的代码看起来像这样:
def initialize
@data_lock = Mutex.new
@closed = false
end
def get_response
@data_lock.synchronize do
@blocked_thread = Thread.current
end
# This loop is a safe guard against accidental wakeup of thread
loop do
@data_lock.synchronize do
if @closed
return @response
end
end
# FIXME: If context switch happens here the thread will be permanently frozen.
Thread.stop # Stop current thread and wait for call to close()
end
end
def close(response)
@data_lock.synchronize do
@closed = true
@response = response
Thread.pass # An attempt at minimizing the risk of permanently freezing threads
if @blocked_thread.is_a? Thread and @blocked_thread.status == 'sleep'
@blocked_thread.wakeup
end
end
end
它应该工作的方式是调用get_response将阻塞当前线程,当另一个线程调用close()时,第一个线程应该被唤醒并返回通过@response发送的值。
这应该适用于所有情况,除非在第一个线程停止之前第二个线程调用close并且在第一个线程停止之前有一个上下文切换的极少数情况下。我怎样才能删除这个(授予非常不可能)的可能性?
答案 0 :(得分:0)
与线程通信的最简单方法是使用Thread#Queue对象。 Thread#Queue是一个线程安全的FIFO队列。
require "thread"
@queue = Queue.new
当胎面想要阻止直到发出信号时,它会从队列中读取。队列为空时线程将停止:
@queue.deq
要唤醒线程,请在队列中写入内容:
@queue.enq :wakeup
在这里,我们只是将一个符号扔进了队列。但是您也可以将内容写入您希望线程处理的队列中。例如,如果一个线程正在处理URL,它可以从队列中检索它们:
loop do
url = @queue.deq
# process the url
end
其他一些线程可以将URL添加到队列中:
@queue.enq "http://stackoverflow.com"
@queue.enq "http://meta.stackoverflow.com"