2010-08-14 100 views
16

調用Thread.join阻塞當前(主)線程。但是,在主線程退出時,不會調用所有衍生線程中的聯結結果。如何在Ruby中生成持久化子線程而不阻塞主線程?Thread.join阻止主線程

以下是加入的典型用法。

for i in 1..100 do 
    puts "Creating thread #{i}" 
    t = Thread.new(i) do |j| 
    sleep 1 
    puts "Thread #{j} done" 
    end 
    t.join 
end 
puts "#{Thread.list.size} threads" 

這給

  Creating thread 1 
    Thread 1 done 
    Creating thread 2 
    Thread 2 done 
    ... 
    1 threads 

但是我正在尋找如何得到這個

 
    Creating thread 1 
    Creating thread 2 
    ... 
    101 threads 
    Thread 1 done 
    Thread 2 done 
    ... 

的代碼提供同樣的輸出在兩個紅寶石1.8.7和1.9.2

回答

18

你只需積累的線程在另一個容器中,然後join他們一個接一個,他們已經全部被創建之後:

my_threads = [] 
for i in 1..100 do 
    puts "Creating thread #{i}" 
    my_threads << Thread.new(i) do |j| 
     sleep 1 
     puts "Thread #{j} done" 
    end 
end 
puts "#{Thread.list.size} threads" 

my_threads.each do |t| 
    t.join 
end 

也不能線程綁定到i因爲i會不斷被覆蓋,並且您的輸出將爲100行「線程100完成」;相反,您必須將其綁定到i的副本,我已巧妙地將其命名爲j

+0

是的,這有效。 我原以爲Ruby會有一種隱式處理方式,而不必跟蹤線程並在最後執行聯合調用。 是的,我不應該在每個線程中使用全局我。基本的東西。感謝您的乾淨修復。我會更新代碼。 – Alkaline 2010-08-14 03:52:40

+5

在Ruby 1.9中,塊參數總是本地的,所以你不需要重命名變量。不過,你會得到一個警告。 (*變量'我'陰影外部變量*或類似的東西。) – 2010-08-14 19:01:03

6

您需要加入循環以外的線程。

for i in 1..100 do 
    puts "Creating thread #{i}" 
    t = Thread.new(i) do |mi| 
    sleep 1 
    puts "Thread #{mi} done" 
    end 
end 

# Wait for all threads to end 
Thread.list.each do |t| 
    # Wait for the thread to finish if it isn't this thread (i.e. the main thread). 
    t.join if t != Thread.current 
end