创建一个包含一些线程、执行任务并最终调用回调方法的类是我目前的目标,在这条路上没什么特别的。
我的实验班对给定 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
(因此没有错误捕获的异常)。
在这种情况下,我注意到最后一个线程处于运行状态。由于我没有要求线程的价值,所以我只是不明白这里的窍门。
有关此问题的任何文档/信息?另外,给它起个名字就好了。