1

创建一个包含一些线程、执行任务并最终调用回调方法的类是我目前的目标,在这条路上没什么特别的。

我的实验班对给定 IP 的特定端口进行了一些连接检查,以提供状态信息。

所以我的尝试:

check = ConnectionChecker.new do | threads |
   # i am done callback
end

check.check_connectivity(ip0, port0, timeout0, identifier0)
check.check_connectivity(ip1, port1, timeout1, identifier1)
check.check_connectivity(ip2, port2, timeout2, identifier2)

sleep while not check.is_done

也许不是最好的方法,但总的来说它适合我的情况。

那么发生了什么:

在我的班级中,我存储了一个回调,执行操作并执行内部操作:

Thread.new-> 成功/失败 -> 标记为完成,全部完成后 -> 调用回调:

 class ConnectionChecker

   attr_reader :is_done

   def initialize(&callback)
     @callback     = callback
     @thread_count = 0
     @threads      = []
     @is_done      = false
   end

   def check_connectivity(host, port, timeout, ident)
     @thread_count += 1
     @threads << Thread.new do

       status = false
       pid    = Process.spawn("nc -z #{host} #{port} >/dev/null")

       begin
         Timeout.timeout(timeout) do
           Process.wait(pid)
           status = true
         end
       rescue Process::TimeoutError => e
         Process.kill('TERM', pid)
       end

       mark_as_done
       #returnvalue for the callback.
       [status, ident]
     end
   end

   # one less to go..
   def mark_as_done
     @thread_count -= 1
     if @thread_count.zero?
       @is_done = true
       @callback.call(@threads)
     end
   end
 end

这段代码——是的,我知道没有启动方法,所以我必须相信我会立即调用它——工作正常。

但是当我交换这两行时:

  @is_done = true
  @callback.call(@threads)

  @callback.call(@threads)
  @is_done = true

然后最后一行,

sleep while not check.is_done

变成一个无限循环。调试显示回调被正确调用,当我检查 的值时is_done,它确实总是false。由于我没有将其放入闭包中,因此我想知道为什么会这样。

回调本身也可以为空,is_done保持不变false(因此没有错误捕获的异常)。

在这种情况下,我注意到最后一个线程处于运行状态。由于我没有要求线程的价值,所以我只是不明白这里的窍门。

有关此问题的任何文档/信息?另外,给它起个名字就好了。

4

1 回答 1

1

尝试使用 Mutex 来确保线程安全:)

于 2012-08-07T12:27:48.367 回答