2012-08-07 84 views
1

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

我的实验类对给定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(所以没有误捕的例外)。

在这种情况下,我注意到最后一个线程处于状态运行状态。由于我没有要求线程的价值,我只是没有得到挂在这里。

有关此问题的任何文档/信息?另外,它的名字会很好。

+0

如果不使用互斥锁,则无法预测线程行为。考虑不同的ruby实现。 – pguardiario 2012-08-07 11:49:02

+0

@pguardiario啊完美,非常感谢。现在它按照我想要的顺序工作。如果你想要点,把它作为答案;) – thedanielhanke 2012-08-07 12:04:25

回答

1

尝试使用互斥锁来确保线程安全:)

+0

没有看到即将到来:D – thedanielhanke 2012-08-07 13:58:50