关于ruby多线程编程中的join

2014-08-30

并发,在操作系统中,是指一个时间段中有几个程序都处于已启动运行到运行完毕之间,且这几个程序都是在同一个处理机上运行,但任一个时刻点上只有一个程序在处理机上运行。

如果只是创建并运行一个线程


先看一个简单的示例:

# !/usr/bin/env ruby
# coding: UTF-8

Thread.new() do
    1000.times do |value|
        puts "---" + value.to_s
    end
end

puts "I am the main thread"

我运行了多次,结果都是:

I am the main thread

原因很简单,主线程和使用Thread.new()创建的子线程并发,当主线程结束后,整个程序会退出。

sleep()


为了让子线程完成后,整个程序再退出,可以:

# !/usr/bin/env ruby
# coding: UTF-8

Thread.new() do
    1000.times do |value|
        puts "---" + value.to_s
    end
end
sleep(3.0)
puts "I am the main thread"

这时候,运行结果就是我们想要的了:

... 省略部分运行结果 ...
---996
---997
---998
---999
I am the main thread

sleep()会让调用它的程序休眠一段时间,sleep(3.0)就是休眠3秒。由于并不知道子线程的运行时间具体是多少,所以sleep()的方式并不好。

while


另外一个思路是主线程监视子线程是否运行结束,若没结束,主线程便不会退出。直接调用线程相关的方法查看其状态:

# !/usr/bin/env ruby
# coding: UTF-8

a = Thread.new() do
    1000.times do |value|
        puts "---" + value.to_s
    end
end

while a.status != false 
    # do something
end
puts 'I am the main thread'

运行结果如下:

... 省略部分运行结果 ...
---996
---997
---998
---999
I am the main thread

也可以用一个变量来监视子线程的状态:

# !/usr/bin/env ruby
# coding: UTF-8

run = true;
a = Thread.new() do
    1000.times do |value|
        puts "---" + value.to_s
    end
    run = false;
end

while run != false 
    # do something
end
puts 'I am the main thread'

join()


下面用join()来解决这个问题:

# !/usr/bin/env ruby
# coding: UTF-8

a = Thread.new() do
    1000.times do |value|
        puts "---" + value.to_s
    end
end

a.join()

puts 'I am the main thread'

运行结果是:

... 省略部分运行结果 ...
---996
---997
---998
---999
I am the main thread

值得注意的是,这种方法中,在join()后主线程休眠,子线程运行结束后,主线程才继续运行。而不像之前那样,主线程和子线程是交替运行的。由于上面的代码中循环次数太少,可能看不出区别,可以运行下面的两段代码进行比较:

# !/usr/bin/env ruby
# coding: UTF-8

# 主线程和子线程交替运行

run = true;
a = Thread.new() do
    10000.times do |value|
        puts "---" + value.to_s
    end
    run = false;
end

while run != false 
    # do something
    puts 'I am the main thread'
end
# !/usr/bin/env ruby
# coding: UTF-8

puts '主线程开始'

a = Thread.new() do
    10000.times do |value|
        puts "---" + value.to_s
    end
end

a.join()

puts 'I am the main thread'

如果使用join()会导致这样一个问题,那么如果两个子线程都join,会怎么样:

# !/usr/bin/env ruby
# coding: UTF-8

a = Thread.new() do
    10000.times do |value|
        puts "a" + value.to_s
    end
end

b = Thread.new() do
    10000.times do |value|
        puts "---" + value.to_s
    end
end

a.join()
b.join()

puts 'I am the main thread'

运行后,可以看到,两个子线程是交替执行的,子线程都结束后,主线程才输出I am the main thread

( 完 )