暂停Ruby中处理队列的线程

时间:2017-10-19 03:33:26

标签: ruby multithreading

说我有一个班级Talker。我正在使用一个队列让Talker说话,但我偶尔想让说话者静音,但是当我取消对说话者的静音时,我希望说话者能够从他离开的地方继续前进。如何阻止线程从队列中获取消息并等待我取消静音以恢复通话?

class Talker
  def initialize
    @queue = Queue.new
    @threads = Array.new(1) do
      Thread.new do
        until @queue.empty?
          # what logic should go here to check if mute
          # and stop taking messages?
          next_msg = @queue.shift

          puts next_msg
        end
      end
    end
  end

  def speak(msg)
    @queue.push(msg)
  end

  # stop threads from taking messages from queue
  def mute
    # what goes here?
  end

  # allow threads to continuing taking messages from queue
  def unmute
    # what goes here?
  end
end

2 个答案:

答案 0 :(得分:0)

虽然ruby绝对不是处理异步操作的最佳选择,但仍然可以使用Thread::Mutex

@handler = Class.new do
  @locks = {}

  def mute(id, mutex)
    @locks[id] ||= mutex.lock
  end

  def unmute(id)
    @locks[id].unlock if @locks[id].is_a?(Thread::Mutex)
    @locks.delete(id)
  end
end


Thread.new do
  MX = Thread::Mutex.new
  until @queue.empty?
    MX.synchronize do
      next_msg = @queue.shift
      puts next_msg
    end
  end
end

# stop threads from taking messages from queue
def mute
  @handler.mute(self, MX)
end

# allow threads to continuing taking messages from queue
def unmute
  @handler.unmute(self)
end

代码未经测试,但我相信它应该可行。

答案 1 :(得分:0)

不是每个线程都有一个互斥锁,而是可以使用由互斥锁保护的简单标志

class Talker
  def initialize
    @muted = false
    @muted_mutex = Thread::Mutex.new

    @queue = Queue.new
    @threads = Array.new(1) do
      Thread.new do
        until @queue.empty?
          next if @muted # skip this iteration
          puts @queue.shift
        end
      end
    end
  end

  def mute
    @muted_mutex.synchronize { @muted = true }
  end

  def unmute
    @muted_mutex.synchronize { @muted = false }
  end
end

这与每个线程的互斥锁之间的区别在于,只有当多个线程(其他地方)尝试同时静音/取消静音时,这才会阻止。但是,在设置@muted = false和读取它的线程之间存在争用时,静音和线程实际停止之间也可能会略有延迟。

这可能不是一个好习惯,但如果我是你,我甚至会放弃互斥锁。对于布尔标志,如果同时发生多次写入,则没有区别。