【问题标题】:Safely wake thread in Ruby在 Ruby 中安全唤醒线程
【发布时间】:2016-03-01 16:10:12
【问题描述】:

我需要让一个线程自行停止,然后被另一个线程唤醒。我的问题是我找不到一个完全万无一失的好解决方案。我现在的代码如下所示:

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 并且在第一个线程停止之前有一个上下文切换。我怎样才能消除这种(非常不可能)的可能性?

【问题讨论】:

    标签: ruby multithreading concurrency mutex


    【解决方案1】:

    与线程通信的最简单方法是使用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"
    

    【讨论】:

    • 谢谢,这正是我所需要的!
    • @AndreasHagelberg 我很高兴它有帮助!如果你愿意,你可以点击上三角来投票(这就是我们在这里表达赞赏的方式)。还有一个复选标记,您可以单击以表明这是对您有帮助的最佳答案。
    • 我已经对其投了赞成票,但不幸的是,我还没有足够的声誉让它公开可见。虽然我错过了复选标记,但我现在已经检查过了。
    • @AndreasHagelberg 有趣...我不知道投票可能是不可见的。感谢您的勾选,欢迎来到 SO!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-07-29
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多