Ruby线程
1. 创建线程
Thread.new do
3.times do
sleep 3
puts "Thread #{Thread.current.object_id} running..."
end
end
ruby使用在Thread.new创建线程,线程创建后立即返回,线程也同时开始执行。ruby线程可以在创建块中使用外部变量,也可以使用本地变量,值变量在线程内部保存的是本地副本,而引用变量保存的是一个本地引用。
class Book
attr_accessor :name
end
num = 0
count = 0
book = Book.new
book.name = 'ybur'
puts "main Thread=#{num} count=#{count} book=#{book.name}"
t.Thread.new(num,book) do |n,b|
n+=1
count+=1
b.name.reverse!
puts "new Thread:num=#{n} count=#{count} book=#{b.name}"
end
t.join
puts "main Thread:num=#{num} count=#{count} book=#{book.name}"
#=>main Thread:num=0 count=0 book=ybur
#=>new Thread:num=1 count=1 book=ruby
#=>main Thread:num=0 count=1 book=ruby
新线程中保存num的副本,在线程中更改num并不影响外部num值,而新线程对book的修改会直接影响外部book,在新线程中也可打破作用域直接访问外部count并作出修改。
常用方法
Thread.current #获取当前线程
Thread.list #所有线程列表
Thread#status #线程状态
Thread#alive?
Thread#stop?
Thread#join
线程可以将某些信息放在自身的hash表中,让别的线程访问。使用Thread#value(阻塞方法)访问线程执行最后一行代码的结果:
t=Thread.new(1,10) do |a,b|
sleep 3
Thread.current['plus_result']=a+b
"thread result:#{a+b}"
end
t.join
puts "1+10=#{t['plus_result']}"
puts "#{t.value}"
#=> 1+10=11
#=> thread result:11
2. Mutex
来自ruby-doc的例子
require 'thread'
mutex=Mutex.new
count1=count2=0
difference=0
counter=Thread.new do
loop do
mutex.synchronize do
count1+=1
count2+=1
end
end
end
spy=Thread.new do
loop do
mutex.synchronize do
difference+=(count1-count2).abs
end
end
end
sleep 1
mutex.lock
#=> count1 >> 21192
#=> count2 >> 21192
#=> difference >>0
3. Condition Variables
来自ruby-doc
require 'thread'
mutext=Mutex.new
cv=ConditionVariable.new
a=Thread.new {
mutex.synchronize {
puts "A:I have critical section, but will wait for cv"
cv.wait mutex
puts "A:I have critical section again! I rule!"
}
}
puts "(Later, back at the ranch...)"
b=Thread.new {
mutex.synchronize {
puts "B: Now I am critical, but am done with cv"
cv.signal
puts "B: I am still critical, finishing up"
}
}
a.join
b.join
produces:
A:I have critical section, but will wait for cv(Later, back at the ranch...)
B: Now I am critical,but am done with cv
B:I am still critical, finishing up
A: I have critical section again! I Rule!
在进入临界区并在cv上等待时,会释放该互斥锁mutex,从而才能让别的线程进入临界区,不至于发生死锁。
4. Queue
ruby的Queue和java的BlockingQueue十分类似。当Queue为空时,执行pop操作会导致线程挂起等待。
require 'thread'
queue=Queue.new
producer=Thread.new do
5.times do |i|
sleep 4
queue << i # operator << is alias of push
puts "#{i} produced"
end
end
consumer=Thread.new do
5.times do |i|
value=queue.pop
sleep 2
puts "consumed #{value}"
end
end
ruby还提供了一个SizedQueue,当达到队列最大长度后,执行push操作时也会导致线程挂起。