Ruby 线程的生命周期及其状态
线程的生命周期提供了线程从出生到结束的简要描述。一个新的线程可以在 Thread.new 或 Thread.start ,或 Thread.fork 方法的帮助下被创建。创建后不需要启动一个新的线程。当CPU的资源可用时,一个线程就会自动开始运行。Thread.new的引用值是一个Thread对象。Thread类提供了各种方法来查询和操作线程。
一个线程运行到与调用Thread.new有关的代码块中,然后停止运行。线程块中最后一个表达式的值就是该线程的值,该值是通过调用Thread对象的value方法获得的。只有当线程完全运行后,value方法才会返回值,否则它不会向完全运行的线程返回值。如果线程中出现了异常,那么它就会终止运行中的线程。这个条件只对那些不是主线程的线程起作用,而且只有那些包含异常的线程才会终止。
线程状态
在Ruby中,线程有五种状态,显示线程的状态。你可以使用 alive? 和 status 方法来检查线程的状态。
- 可运行的:当前正在运行的线程,或准备在CPU资源可用时占用其资源的线程。
- 休眠: 当前正在休眠的线程,或者正在等待IO的线程,或者本身已经停止的线程。
- 中止:是一种中间状态。一个中止的线程,它已经被杀死,但还没有终止。
- 异常终止:一个包含异常的线程,或者换句话说,一个由于异常的出现而被终止的线程。
- 正常终止:正常终止的线程,或不包含异常并完成其工作的线程。
示例:
# Ruby program to illustrate
# check status of thread
counter = 0
# creating new thread
x = Thread.new { loop { counter += 1 } }
# check thread alive or not
puts x.alive?
输出:
true
下表显示了状态的名称和它们的返回值。
状态 | 返回值 |
---|---|
可运行 | 运行 |
睡眠状态 | 睡眠 |
中止 | 中止 |
正常终止 | 错误 |
异常终止 | nil |
主线程
在Ruby中,主线程是多线程的一个特殊部分。它是一个程序的最顶层线程,所有的子线程都在这个线程下运行,或者换句话说,它是父线程,同一程序的其他线程是主线程的子线程。主线程是在main方法的帮助下创建的。当主线程的工作完成后,Ruby解释器就会停止运行,这意味着主线程和子线程完成了它们的任务。类方法Thread.main返回代表主线程的Thread对象。如果在主线程中出现了异常,并且没有在任何地方得到处理,那么Ruby解释器会打印一条消息或退出。如果在主线程以外的其他线程中出现了异常,那么Ruby解释器将终止包含异常的线程。
例子
# Ruby program to illustrate
# main thread
# Create main thread
puts Thread.main
puts ""
# create new thread
a1 = Thread.new {sleep 200}
list_thread= Thread.list
list_thread.each {|t| p t }
puts "Current thread = " + Thread.current.to_s
# create new thread
a2 = Thread.new {sleep 200}
list_thread= Thread.list
list_thread.each {|t| p t }
puts "Current thread=" + Thread.current.to_s
# kill thread a1
Thread.kill(a1)
# pass execution to thread a2
Thread.pass
# kill thread a2
Thread.kill(a2)
list_thread= Thread.list
list_thread.each {|t| p t }
# exit main thread
Thread.exit
输出
#<Thread:0x00000001afe1b8>
#<Thread:0x00000001afe1b8 run>
#<Thread:0x00000001d05c68@/var/www/service/usercode/1749234900/source.rb:9 sleep>
Current thread = #<Thread:0x00000001afe1b8>
#<Thread:0x00000001afe1b8 run>
#<Thread:0x00000001d05c68@/var/www/service/usercode/1749234900/source.rb:9 sleep>
#<Thread:0x00000001c8bd50@/var/www/service/usercode/1749234900/source.rb:15 run>
Current thread=#<Thread:0x00000001afe1b8>
#<Thread:0x00000001afe1b8 run>
#<Thread:0x00000001c8bd50@/var/www/service/usercode/1749234900/source.rb:15 dead>
解释: 这个程序显示了主线程是如何执行的。首先,我们创建了一个主线程,然后在这个主线程中,有两个子线程,即a1和a2。当线程a1完全执行时,就杀死a1线程,并将执行任务交给a2线程。之后,杀死a2线程,并打印主线程中存在的线程列表和它们的状态。当所有存在于主线程中的线程都死了,那么主线程就存在了。
替代线程状态。暂停、唤醒和杀戮
我们知道,线程是在可运行状态下创建的,并准备运行。一个线程通过进入睡眠状态,或通过调用Thread.stop方法,或通过调用Kernel.sleep来暂停自己。任何线程都不能被其他线程强行暂停。如果一个线程在调用Kernel.sleep时没有任何参数,那么它将永远暂停该线程,直到被唤醒;如果一个线程在调用Kernel.sleep时有一个参数,那么它将暂时使该线程进入睡眠状态。处于临时睡眠状态的线程在给定的时间过后会自动醒来,并重新进入可运行状态。
一个通过调用Thread.stop或调用kernel.sleep暂停的线程可以通过调用实例方法再次启动,即唤醒和运行。这些方法将一个线程的状态从睡眠状态切换到可运行状态。运行方法也会调用线程调度器。由于调用了线程调度器,最近被唤醒的线程可能会获得CPU资源。wakeup方法在不调用线程调度器的情况下唤醒了特定的线程。
一个线程可以通过调用实例方法kill强行终止其他线程。终止和退出方法与kill方法类似。这些方法将被杀的方法放入正常终止状态。杀死一个线程是很危险的事情,除非你有办法知道该线程不在文件共享状态中。用!方法杀死一个线程是更有害的,因为一个被杀死的线程可能会使套接字、文件和其他资源开放。