在 Ruby 中安全唤醒线程
Safely wake thread in Ruby
我需要一个线程自己停止,然后被另一个线程唤醒。我遇到的问题是我找不到一个完全万无一失的好解决方案。我现在的代码看起来像这样:
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() 时,第一个线程应该被唤醒并且 return 发送的值通过@response.
这应该适用于所有情况,除非是在第一个线程停止之前第二个线程调用关闭并且在第一个线程停止之前存在上下文切换的极少数情况。我怎样才能消除这种(被认为不太可能)的可能性?
与线程通信的最简单方法是使用 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://whosebug.com"
@queue.enq "http://meta.whosebug.com"
我需要一个线程自己停止,然后被另一个线程唤醒。我遇到的问题是我找不到一个完全万无一失的好解决方案。我现在的代码看起来像这样:
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() 时,第一个线程应该被唤醒并且 return 发送的值通过@response.
这应该适用于所有情况,除非是在第一个线程停止之前第二个线程调用关闭并且在第一个线程停止之前存在上下文切换的极少数情况。我怎样才能消除这种(被认为不太可能)的可能性?
与线程通信的最简单方法是使用 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://whosebug.com"
@queue.enq "http://meta.whosebug.com"