【问题标题】:Thread.join blocks the main threadThread.join 阻塞主线程
【发布时间】:2010-08-14 03:13:44
【问题描述】:

调用 Thread.join 会阻塞当前(主)线程。然而,当主线程退出时,不调用 join 会导致所有生成的线程都被杀死。如何在 Ruby 中生成持久子线程而不阻塞主线程?

这是一个典型的 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"

这给了

 创建线程 1
     线程 1 完成
     创建线程 2
     线程 2 完成
     ...
     1 个线程

但我正在寻找如何获得这个

创建线程 1 创建线程 2 ... 101 个线程 线程 1 完成 线程 2 完成 ...

代码在 Ruby 1.8.7 和 1.9.2 中给出相同的输出

【问题讨论】:

    标签: ruby multithreading


    【解决方案1】:

    您只需将线程累积在另一个容器中,然后在它们全部创建后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

    【讨论】:

    • 是的,这行得通。我原以为 Ruby 有办法隐式处理这个问题,而不必跟踪线程并在最后执行 join 调用。是的,我不应该在每个线程中使用全局 i 。基本的东西。感谢您的干净修复。我会更新代码。
    • 在 Ruby 1.9 中,块参数始终是本地的,因此您不需要重命名变量。不过,你会收到警告。 (变量i遮蔽外部变量或类似的东西。)
    【解决方案2】:

    你需要加入循环之外的线程。

    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
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2018-02-16
      • 1970-01-01
      • 2015-12-29
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多