2

这个想法是输入将由控制台提供,并将使用唯一的“id”作为输入的第一个单词来标识。当遇到新的 id 时会产生一个新线程,随后的输入是“开始”。当具有相同 id 的输入会说“关闭”时,线程应该关闭。语句的顺序是随机的。

4

1 回答 1

3

这里的诀窍是让一个线程(最容易的是主线程)完成所有读取。该线程将解析命令,启动或停止线程,并将命令分派给线程。每个线程都有自己的队列,它从中读取命令,主线程将命令放入其中。让我们看看它是如何完成的。

我们将从控制命令的一个小模块开始,以便它们是 DRY:

module ControlCommands
  START_COMMAND = 'start'
  STOP_COMMAND = 'stop'
end

现在让我们看看“主要”:

class Main

  def initialize
    @workers = Workers.new
    @console = Console.new(@workers)
  end

  def run
    @console.read_and_dispatch
    @workers.join
  end

end

Main.new.run

这里没什么大不了的。我们制作了一个控制台,并告诉它读取命令并将它们分派给工作人员。控制台在输入用完之前不会从那里返回。@workers.join在程序退出之前确保所有工作人员已完成工作并正确关闭的调用。

这是控制台类:

class Console

  def initialize(workers)
    @workers = workers
  end

  def read_and_dispatch
    while input = gets
      @workers.dispatch *parse_input(input)
    end
  end

  private

  def parse_input(input)
    input.match(/^(\w+) *(.*)$/)[1..2]
  end

end

read_and_dispatch是主循环。它只负责读取和解析输入。只要有输入,它就将其拆分为工人名称和命令,然后告诉工人处理命令。

这是工人类:

class Workers

  include ControlCommands

  def initialize
    @workers = {}
  end

  def dispatch(worker_name, command)
    case command
    when START_COMMAND
      start_worker worker_name
    when STOP_COMMAND
      stop_worker worker_name
    else
      dispatch_worker worker_name, command
    end
  end

  def join
    @workers.each do |worker_name, worker|
      worker.stop
      worker.join
    end
  end

  private

  def start_worker(worker_name)
    @workers[worker_name] = Worker.new(worker_name)
  end

  def stop_worker(worker_name)
    @workers[worker_name].stop
  end

  def dispatch_worker(worker_name, command)
    @workers[worker_name].dispatch command
  end

end

这是大部分肉的地方。此类创建工作者(线程)、停止它们并向它们发送命令。注意这里没有错误处理:如果你试图停止一个没有启动的线程,启动一个已经启动的线程,或者向一个不存在的线程发送一个命令,程序将会崩溃或者行为不端。我会将这些情况的处理留作“读者练习”。

这是工人类:

class Worker

  include ControlCommands

  def initialize(name)
    @name = name
    @commands = Queue.new
    @thread = start_thread
  end

  def dispatch(command)
    @commands.enq command
  end

  def stop
    @commands.enq STOP_COMMAND
  end

  def join
    @thread.join
  end

  private

  def start_thread
    Thread.new do
      loop do
        command = @commands.deq
        break if command == STOP_COMMAND
        process_command command
      end
    end
  end

  def process_command(command)
    print "thread #{@name} received command #{command.inspect}\n"
  end

end

此类包含线程,以及用于在主线程(读取控制台的线程)和工作线程之间进行通信的队列。该队列还用于同步停止线程,方法是将 STOP_COMMAND 放入队列中,线程通过退出来响应该队列。当您负担得起时,最好同步而不是异步停止线程。

这是一个简单的输入文件:

foo start
bar start
foo input
bar input
foo stop
bar stop

以及当程序带有该输入时的输出:

thread bar received command "input"
thread foo received command "input"
于 2012-12-12T14:58:46.120 回答