2012-08-07 57 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