Thread
class Thread
Parent:Object
线程是并发编程模型的Ruby实现。
需要多个执行线程的程序是Ruby的Thread类的完美候选者。
例如,我们可以使用::new创建一个与主线程执行独立的新线程。
thr = Thread.new { puts "Whats the big deal" }
然后,我们可以暂停主线程的执行,并允许我们的新线程使用连接完成:
thr.join #=> "Whats the big deal"
如果我们thr.join
在主线程终止之前没有调用,那么包含的所有其他线程thr
都将被终止。
或者,您可以使用数组一次处理多个线程,如下例所示:
threads = []
threads << Thread.new { puts "Whats the big deal" }
threads << Thread.new { 3.times { puts "Threads are fun!" } }
创建几个线程后,我们等待它们全部连续完成。
threads.each { |thr| thr.join }
线程初始化
为了创建新线程,Ruby提供了::new,::start和::fork。每个方法都必须提供一个块,否则会引发ThreadError。
当继承Thread类时,子类的initialize
方法将被::start和::fork忽略。否则,一定要在你的initialize
方法中调用超级。
线程终止
为了终止线程,Ruby提供了多种方法来执行此操作。
类方法::kill意味着退出给定的线程:
thr = Thread.new { ... }
Thread.kill(thr) # sends exit() to thr
或者,您可以使用实例方法exit或其任何别名kill或terminate。
thr.exit
线程状态
Ruby提供了一些查询给定线程状态的实例方法。获取当前线程状态使用状态的字符串
thr = Thread.new { sleep }
thr.status # => "sleep"
thr.exit
thr.status # => false
你还可以使用 alive?告诉线程是否正在运行或正在睡眠并stop?如果线程死亡或睡眠。
线程变量和范围
由于线程是用块创建的,所以对于变量作用域的其他Ruby块也适用相同的规则。任何在这个块内创建的局部变量都只能被这个线程访问。
Fiber-local vs. Thread-local
每个光纤都有自己的存储桶来存储#[]。当您设置一个新的光纤本地时,它只能在该光纤内访问。为了显示:
Thread.new {
Thread.current[:foo] = "bar"
Fiber.new {
p Thread.current[:foo] # => nil
}.resume
}.join
这个例子使用[]获取,[] =用于设置光纤本地,您还可以使用键列出给定线程和键的光纤本地?检查是否存在光纤本地。
当涉及到线程本地化时,它们可以在线程的整个范围内访问。给出以下示例:
Thread.new{
Thread.current.thread_variable_set(:foo, 1)
p Thread.current.thread_variable_get(:foo) # => 1
Fiber.new{
Thread.current.thread_variable_set(:foo, 2)
p Thread.current.thread_variable_get(:foo) # => 2
}.resume
p Thread.current.thread_variable_get(:foo) # => 2
}.join
你可以看到线程局部:foo
转移到了光纤中,并2
在线程结束时被改变了。
这个例子使用thread_variable_set来创建新的线程局部变量,并使用thread_variable_get来引用它们。
还有thread_variables列出所有线程 - 本地和thread_variable?检查给定的线程本地是否存在。
异常处理
任何线程都可以使用raise实例方法引发异常,其操作方式与Kernel#raise类似。
但是,需要注意的是,除主线程之外的任何线程中发生的异常都依赖于abort_on_exception。这个选项是false
默认的,这意味着任何未处理的异常都会导致线程在由连接或值等待时以无提示方式终止。您可以通过abort_on_exception = true
或将$ DEBUG设置为来更改此默认值true
。
通过添加类方法:: handle_interrupt,您现在可以与线程异步处理异常。
调度
Ruby提供了几种方法来支持程序中的调度线程。
第一种方法是使用类方法::stop,将当前正在运行的线程休眠并安排另一个线程的执行。
一旦某个线程处于睡眠状态,您可以使用实例方法唤醒将您的线程标记为符合调度的条件。
您还可以尝试::pass,它会尝试将执行传递给另一个线程,但依赖于操作系统是否正在运行的线程将会切换。优先级也是一样,它可以让你在传递执行时向线程调度器提示你想要优先执行的线程。此方法也取决于操作系统,可能会在某些平台上被忽略。
公共类别方法
DEBUG → num Show source
返回线程调试级别。仅在使用THREAD_DEBUG = -1编译时才可用。
static VALUE
rb_thread_s_debug(void)
{
return INT2NUM(rb_thread_debug_enabled
}
DEBUG = num Show source
设置线程调试级别。仅在使用THREAD_DEBUG = -1编译时才可用。
static VALUE
rb_thread_s_debug_set(VALUE self, VALUE val)
{
rb_thread_debug_enabled = RTEST(val) ? NUM2INT(val) : 0;
return val;
}
abort_on_exception → true or false Show source
返回全局“abort on exception”状态。
默认是false
。
设置true
为时,如果有任何线程被异常中止,则引发的异常将在主线程中重新生成。
也可以通过全局$ DEBUG标志或命令行选项来指定-d
。
另见::abort_on_exception =。
还有一个实例级别的方法可以为特定线程设置此方法,请参阅abort_on_exception。
static VALUE
rb_thread_s_abort_exc(void)
{
return GET_THREAD()->vm->thread_abort_on_exception ? Qtrue : Qfalse;
}
abort_on_exception= boolean → true or false Show source
设置true
为时,如果有任何线程被异常中止,则引发的异常将在主线程中重新生成。返回新的状态。
Thread.abort_on_exception = true
t1 = Thread.new do
puts "In new thread"
raise "Exception from thread"
end
sleep(1)
puts "not reached"
这将产生:
In new thread
prog.rb:4: Exception from thread (RuntimeError)
from prog.rb:2:in `initialize'
from prog.rb:2:in `new'
from prog.rb:2
另见::abort_on_exception。
还有一个实例级别的方法可以为特定的线程进行设置,请参阅abort_on_exception =。
static VALUE
rb_thread_s_abort_exc_set(VALUE self, VALUE val)
{
GET_THREAD()->vm->thread_abort_on_exception = RTEST(val
return val;
}
current → thread Show source
返回当前正在执行的线程。
Thread.current #=> #<Thread:0x401bdf4c run>
static VALUE
thread_s_current(VALUE klass)
{
return rb_thread_current(
}
exclusive { block } → obj Show source
在单个VM全局Thread::Mutex#同步中封装块,并返回块的值。在专用部分内部执行的线程只会阻止其他也使用::exclusive机制的线程。
# File prelude.rb, line 11
def self.exclusive
warn "Thread.exclusive is deprecated, use Thread::Mutex", caller
MUTEX_FOR_THREAD_EXCLUSIVE.synchronize{
yield
}
end
exit → thread Show source
终止当前正在运行的线程并安排另一个线程运行。
如果此线程已被标记为被杀死,则::exit将返回线程。
如果这是主线程或最后一个线程,请退出进程。
static VALUE
rb_thread_exit(void)
{
rb_thread_t *th = GET_THREAD(
return rb_thread_kill(th->self
}
fork(args*) {|args| block } → thread Show source
基本上和::new一样。但是,如果Thread类是子类,那么调用start
该子类将不会调用子类的initialize
方法。
static VALUE
thread_start(VALUE klass, VALUE args)
{
return thread_create_core(rb_thread_alloc(klass), args, 0
}
handle_interrupt(hash) { ... } → result of the block Show source
改变异步中断时序。
中断
是指#raise,#kill,信号陷阱(不支持)和主线程终止(如果主线程终止,然后所有其他线程将被终止)的异步事件和相应过程。
给定的hash对有点像ExceptionClass => :TimingSymbol。ExceptionClass是由给定块处理的中断。TimingSymbol可以是以下符号之一:
:immediate
立即调用中断。
:on_blocking
在BlockingOperation时
调用中断。
:never
永远不要调用所有中断。
BlockingOperation
表示该操作将阻止调用线程,如读取和写入。在CRuby实现上,BlockingOperation
是在没有GVL的情况下执行的任何操作。
被屏蔽的异步中断被延迟直到它们被启用。此方法与sigprocmask(3)类似。
NOTE
异步中断很难使用。
如果您需要在线程之间进行通信,请考虑使用另一种方式,如队列。
或者在深入了解这种方法的情况下使用它们。
Usage
在这个例子中,我们可以防止#raise异常。
使用:never
TimingSymbol时,RuntimeError异常将在主线程的第一个块中始终被忽略。在第二个::handle_interrupt块中,我们可以有目的地处理RuntimeError异常。
th = Thread.new do
Thread.handle_interrupt(RuntimeError => :never) {
begin
# You can write resource allocation code safely.
Thread.handle_interrupt(RuntimeError => :immediate) {
# ...
}
ensure
# You can write resource deallocation code safely.
end
}
end
Thread.pass
# ...
th.raise "stop"
虽然我们忽略了RuntimeError异常,但编写我们的资源分配代码是安全的。然后,确保块是我们可以安全地释放资源的位置。
防止Timeout::Error
在下一个示例中,我们将防范Timeout::Error异常。这将有助于防止在正常确保子句期间发生Timeout::Error异常时泄漏资源。对于这个例子,我们使用来自lib/timeout.rb的标准库Timeout的帮助
require 'timeout'
Thread.handle_interrupt(Timeout::Error => :never) {
timeout(10){
# Timeout::Error doesn't occur here
Thread.handle_interrupt(Timeout::Error => :on_blocking) {
# possible to be killed by Timeout::Error
# while blocking operation
}
# Timeout::Error doesn't occur here
}
}
在timeout块的第一部分,我们可以依靠Timeout::Error被忽略。然后在该Timeout::Error => :on_blocking块中,任何会阻止调用线程的操作都会引发Timeout::Error异常。
堆栈控制设置
为了一次控制多个ExceptionClass和TimingSymbol,可以堆叠多个级别的:: handle_interrupt块。
Thread.handle_interrupt(FooError => :never) {
Thread.handle_interrupt(BarError => :never) {
# FooError and BarError are prohibited.
}
}
用ExceptionClass继承
将考虑从ExceptionClass参数继承的所有异常。
Thread.handle_interrupt(Exception => :never) {
# all exceptions inherited from Exception are prohibited.
}
static VALUE
rb_thread_s_handle_interrupt(VALUE self, VALUE mask_arg)
{
VALUE mask;
rb_thread_t *th = GET_THREAD(
volatile VALUE r = Qnil;
int state;
if (!rb_block_given_p()) {
rb_raise(rb_eArgError, "block is needed."
}
mask = 0;
mask_arg = rb_convert_type(mask_arg, T_HASH, "Hash", "to_hash"
rb_hash_foreach(mask_arg, handle_interrupt_arg_check_i, (VALUE)&mask
if (!mask) {
return rb_yield(Qnil
}
OBJ_FREEZE_RAW(mask
rb_ary_push(th->pending_interrupt_mask_stack, mask
if (!rb_threadptr_pending_interrupt_empty_p(th)) {
th->pending_interrupt_queue_checked = 0;
RUBY_VM_SET_INTERRUPT(th
}
TH_PUSH_TAG(th
if ((state = EXEC_TAG()) == 0) {
r = rb_yield(Qnil
}
TH_POP_TAG(
rb_ary_pop(th->pending_interrupt_mask_stack
if (!rb_threadptr_pending_interrupt_empty_p(th)) {
th->pending_interrupt_queue_checked = 0;
RUBY_VM_SET_INTERRUPT(th
}
RUBY_VM_CHECK_INTS(th
if (state) {
TH_JUMP_TAG(th, state
}
return r;
}
kill(thread) → thread Show source
导致给定thread
退出,另见::exit。
count = 0
a = Thread.new { loop { count += 1 } }
sleep(0.1) #=> 0
Thread.kill(a) #=> #<Thread:0x401b3d30 dead>
count #=> 93947
a.alive? #=> false
static VALUE
rb_thread_s_kill(VALUE obj, VALUE th)
{
return rb_thread_kill(th
}
list → array Show source
返回可运行或停止的所有线程的Thread对象数组。
Thread.new { sleep(200) }
Thread.new { 1000000.times {|i| i*i } }
Thread.new { Thread.stop }
Thread.list.each {|t| p t}
这将产生:
#<Thread:0x401b3e84 sleep>
#<Thread:0x401b3f38 run>
#<Thread:0x401b3fb0 sleep>
#<Thread:0x401bdf4c run>
VALUE
rb_thread_list(void)
{
VALUE ary = rb_ary_new(
rb_vm_t *vm = GET_THREAD()->vm;
rb_thread_t *th = 0;
list_for_each(&vm->living_threads, th, vmlt_node) {
switch (th->status) {
case THREAD_RUNNABLE:
case THREAD_STOPPED:
case THREAD_STOPPED_FOREVER:
rb_ary_push(ary, th->self
default:
break;
}
}
return ary;
}
main → thread Show source
返回主线程。
static VALUE
rb_thread_s_main(VALUE klass)
{
return rb_thread_main(
}
new { ... } → thread Show source
new(*args, &proc) → thread
new(*args) { |args| ... } → thread
创建一个执行给定块的新线程。
任何args
给定::new都将被传递给该块:
arr = []
a, b, c = 1, 2, 3
Thread.new(a,b,c) { |d,e,f| arr << d << e << f }.join
arr #=> [1, 2, 3]
如果调用::new没有块,则会引发ThreadError异常。
如果你打算子类Thread,一定要在你的initialize
方法中调用super ,否则会引发ThreadError。
static VALUE
thread_s_new(int argc, VALUE *argv, VALUE klass)
{
rb_thread_t *th;
VALUE thread = rb_thread_alloc(klass
if (GET_VM()->main_thread->status == THREAD_KILLED)
rb_raise(rb_eThreadError, "can't alloc thread"
rb_obj_call_init(thread, argc, argv
GetThreadPtr(thread, th
if (!threadptr_initialized(th)) {
rb_raise(rb_eThreadError, "uninitialized thread - check `%"PRIsVALUE"#initialize'",
klass
}
return thread;
}
pass → nil Show source
给线程调度程序一个提示,将执行传递给另一个线程。正在运行的线程可能会或可能不会切换,这取决于操作系统和处理器。
static VALUE
thread_s_pass(VALUE klass)
{
rb_thread_schedule(
return Qnil;
}
pending_interrupt?(error = nil) → true/false Show source
返回异步队列是否为空。
由于::handle_interrupt可用于推迟异步事件,因此可使用此方法确定是否存在任何延迟事件。
如果你发现这个方法返回true,那么你可能会完成:never
块。
例如,以下方法立即处理延迟的异步事件。
def Thread.kick_interrupt_immediately
Thread.handle_interrupt(Object => :immediate) {
Thread.pass
}
end
如果error
给出,则仅检查error
类型延迟事件。
用法
th = Thread.new{
Thread.handle_interrupt(RuntimeError => :on_blocking){
while true
...
# reach safe point to invoke interrupt
if Thread.pending_interrupt?
Thread.handle_interrupt(Object => :immediate){}
end
...
end
}
}
...
th.raise # stop thread
这个例子也可以写成如下,你应该使用它来避免异步中断。
flag = true
th = Thread.new{
Thread.handle_interrupt(RuntimeError => :on_blocking){
while true
...
# reach safe point to invoke interrupt
break if flag == false
...
end
}
}
...
flag = false # stop thread
static VALUE
rb_thread_s_pending_interrupt_p(int argc, VALUE *argv, VALUE self)
{
return rb_thread_pending_interrupt_p(argc, argv, GET_THREAD()->self
}
report_on_exception → true or false Show source
返回全局“report on exception”状态。
默认是false
。
设置true
为时,如果在任何线程中引发异常,所有线程都将报告异常。
另见::report_on_exception =。
还有一个实例级方法可以为特定线程设置此方法,请参阅report_on_exception。
static VALUE
rb_thread_s_report_exc(void)
{
return GET_THREAD()->vm->thread_report_on_exception ? Qtrue : Qfalse;
}
report_on_exception= boolean → true or false Show source
设置true
为时,如果引发异常,所有线程都会报告异常。返回新的状态。
Thread.report_on_exception = true
t1 = Thread.new do
puts "In new thread"
raise "Exception from thread"
end
sleep(1)
puts "In the main thread"
这将产生:
In new thread
prog.rb:4: Exception from thread (RuntimeError)
from prog.rb:2:in `initialize'
from prog.rb:2:in `new'
from prog.rb:2
In the main thread
另请参见::report_on_exception。
还有一个实例级别的方法可以为特定线程设置它,请参阅report_on_exception =。
static VALUE
rb_thread_s_report_exc_set(VALUE self, VALUE val)
{
GET_THREAD()->vm->thread_report_on_exception = RTEST(val
return val;
}
start(args*) {|args| block } → thread Show source
基本上和::new一样。但是,如果Thread类是子类,那么调用start
该子类将不会调用子类的initialize
方法。
static VALUE
thread_start(VALUE klass, VALUE args)
{
return thread_create_core(rb_thread_alloc(klass), args, 0
}
stop → nil Show source
停止执行当前线程,将其置于“sleep”状态,并安排另一个线程的执行。
a = Thread.new { print "a"; Thread.stop; print "c" }
sleep 0.1 while a.status!='sleep'
print "b"
a.run
a.join
#=> "abc"
VALUE
rb_thread_stop(void)
{
if (rb_thread_alone()) {
rb_raise(rb_eThreadError,
"stopping only thread\n\tnote: use sleep to stop forever"
}
rb_thread_sleep_deadly(
return Qnil;
}
公共实例方法
thrsym → obj or nil Show source
属性参考 - 使用符号或字符串名称返回光纤本地变量(当前线程的根光纤,如果不明确位于光纤内)的值。如果指定的变量不存在,则返回nil
。
[
Thread.new { Thread.current["name"] = "A" },
Thread.new { Thread.current[:name] = "B" },
Thread.new { Thread.current["name"] = "C" }
].each do |th|
th.join
puts "#{th.inspect}: #{th[:name]}"
end
这将产生:
#<Thread:0x00000002a54220 dead>: A
#<Thread:0x00000002a541a8 dead>: B
#<Thread:0x00000002a54130 dead>: C
#[]和#[] =不是线程本地的,但是本地光纤。这种混淆在Ruby 1.8中并不存在,因为光纤只有在Ruby 1.9之后才可用。Ruby 1.9选择这些方法表现为光纤本地以保存动态范围的以下习惯用法。
def meth(newvalue)
begin
oldvalue = Thread.current[:name]
Thread.current[:name] = newvalue
yield
ensure
Thread.current[:name] = oldvalue
end
end
如果方法是线程本地的并且给定的块切换光纤,则该习语可能不能用作动态范围。
f = Fiber.new {
meth(1) {
Fiber.yield
}
}
meth(2) {
f.resume
}
f.resume
p Thread.current[:name]
#=> nil if fiber-local
#=> 2 if thread-local (The value 2 is leaked to outside of meth method.)
对于线程局部变量,请参阅thread_variable_get和thread_variable_set。
static VALUE
rb_thread_aref(VALUE thread, VALUE key)
{
ID id = rb_check_id(&key
if (!id) return Qnil;
return rb_thread_local_aref(thread, id
}
thrsym = obj → obj Show source
属性分配 - 使用符号或字符串设置或创建光纤局部变量的值。
See also #[].
对于线程局部变量,请参阅thread_variable_set和thread_variable_get。
static VALUE
rb_thread_aset(VALUE self, VALUE id, VALUE val)
{
return rb_thread_local_aset(self, rb_to_id(id), val
}
abort_on_exception → true or false Show source
返回线程本地的“abort on exception”条件的状态thr
。
默认是false
。
另请参阅abort_on_exception =。
还有一个类级别的方法来为所有线程设置它,请参阅::abort_on_exception。
static VALUE
rb_thread_abort_exc(VALUE thread)
{
rb_thread_t *th;
GetThreadPtr(thread, th
return th->abort_on_exception ? Qtrue : Qfalse;
}
abort_on_exception= boolean → true or false Show source
如果设置为true
,如果thr
异常中止了异常,则会在主线程中重新引发引发的异常。
另请参阅abort_on_exception。
还有一个类级别的方法来为所有线程设置它,请参阅:::abort_on_exception =。
static VALUE
rb_thread_abort_exc_set(VALUE thread, VALUE val)
{
rb_thread_t *th;
GetThreadPtr(thread, th
th->abort_on_exception = RTEST(val
return val;
}
add_trace_func(proc) → proc Show source
添加proc
作为跟踪处理程序。
请参阅#set_trace_func和Kernel#set_trace_func。
static VALUE
thread_add_trace_func_m(VALUE obj, VALUE trace)
{
rb_thread_t *th;
GetThreadPtr(obj, th
thread_add_trace_func(th, trace
return trace;
}
alive? → true or false Show source
返回true
是否thr
正在运行或正在休眠。
thr = Thread.new { }
thr.join #=> #<Thread:0x401b3fb0 dead>
Thread.current.alive? #=> true
thr.alive? #=> false
另请参见stop?和状态。
static VALUE
rb_thread_alive_p(VALUE thread)
{
rb_thread_t *th;
GetThreadPtr(thread, th
if (rb_threadptr_dead(th))
return Qfalse;
return Qtrue;
}
backtrace → array Show source
返回目标线程的当前回溯。
static VALUE
rb_thread_backtrace_m(int argc, VALUE *argv, VALUE thval)
{
return rb_vm_thread_backtrace(argc, argv, thval
}
backtrace_locations(*args) → array or nil Show source
返回目标线程的执行堆栈 - 一个包含回溯位置对象的数组。
有关更多信息,请参阅Thread::Backtrace::Location。
此方法的行为与Kernel#caller_locations类似,只是它适用于特定的线程。
static VALUE
rb_thread_backtrace_locations_m(int argc, VALUE *argv, VALUE thval)
{
return rb_vm_thread_backtrace_locations(argc, argv, thval
}
exit → thr or nil Show source
kill → thr or nil
terminate → thr or nil
终止thr
并安排另一个线程运行。
如果此线程已被标记为被杀死,则退出返回线程。
如果这是主线程或最后一个线程,则退出该过程。
VALUE
rb_thread_kill(VALUE thread)
{
rb_thread_t *th;
GetThreadPtr(thread, th
if (th->to_kill || th->status == THREAD_KILLED) {
return thread;
}
if (th == th->vm->main_thread) {
rb_exit(EXIT_SUCCESS
}
thread_debug("rb_thread_kill: %p (%"PRI_THREAD_ID")\n", (void *)th, thread_id_str(th)
if (th == GET_THREAD()) {
/* kill myself immediately */
rb_threadptr_to_kill(th
}
else {
threadptr_check_pending_interrupt_queue(th
rb_threadptr_pending_interrupt_enque(th, eKillSignal
rb_threadptr_interrupt(th
}
return thread;
}
group → thgrp or nil Show source
返回nil
包含给定线程的ThreadGroup;如果thr
不是任何组的成员,则返回该线程组。
Thread.main.group #=> #<ThreadGroup:0x4029d914>
VALUE
rb_thread_group(VALUE thread)
{
rb_thread_t *th;
VALUE group;
GetThreadPtr(thread, th
group = th->thgroup;
if (!group) {
group = Qnil;
}
return group;
}
inspect → string Show source
将thr
的名称,ID和状态转储到字符串。
static VALUE
rb_thread_inspect(VALUE thread)
{
VALUE cname = rb_class_path(rb_obj_class(thread)
rb_thread_t *th;
const char *status;
VALUE str;
GetThreadPtr(thread, th
status = thread_status_name(th, TRUE
str = rb_sprintf("#<%"PRIsVALUE":%p", cname, (void *)thread
if (!NIL_P(th->name)) {
rb_str_catf(str, "@%"PRIsVALUE, th->name
}
if (!th->first_func && th->first_proc) {
VALUE loc = rb_proc_location(th->first_proc
if (!NIL_P(loc)) {
const VALUE *ptr = RARRAY_CONST_PTR(loc
rb_str_catf(str, "@%"PRIsVALUE":%"PRIsVALUE, ptr[0], ptr[1]
rb_gc_force_recycle(loc
}
}
rb_str_catf(str, " %s>", status
OBJ_INFECT(str, thread
return str;
}
join → thr Show source
join(limit) → thr
调用线程将挂起执行并运行thr
。
直到thr
退出或直到给定limit
秒数过去才会返回。
如果时限到期,nil
将返回,否则返回thr
。
任何未加入的线程在主程序退出时将被终止。
如果thr
以前引发了一个异常,并且::abort_on_exception或$ DEBUG标志没有被设置(因此该异常还没有被处理),它将在这个时候被处理。
a = Thread.new { print "a"; sleep(10 print "b"; print "c" }
x = Thread.new { print "x"; Thread.pass; print "y"; print "z" }
x.join # Let thread x finish, thread a will be killed on exit.
#=> "axyz"
以下示例说明了limit
参数。
y = Thread.new { 4.times { sleep 0.1; puts 'tick... ' }}
puts "Waiting" until y.join(0.15)
这将产生:
tick...
Waiting
tick...
Waiting
tick...
tick...
static VALUE
thread_join_m(int argc, VALUE *argv, VALUE self)
{
rb_thread_t *target_th;
double delay = DELAY_INFTY;
VALUE limit;
GetThreadPtr(self, target_th
rb_scan_args(argc, argv, "01", &limit
if (!NIL_P(limit)) {
delay = rb_num2dbl(limit
}
return thread_join(target_th, delay
}
key?(sym) → true or false Show source
如果给定的字符串(或符号)作为光纤局部变量存在,则返回true
。
me = Thread.current
me[:oliver] = "a"
me.key?(:oliver) #=> true
me.key?(:stanley) #=> false
static VALUE
rb_thread_key_p(VALUE self, VALUE key)
{
rb_thread_t *th;
ID id = rb_check_id(&key
GetThreadPtr(self, th
if (!id || !th->local_storage) {
return Qfalse;
}
if (st_lookup(th->local_storage, id, 0)) {
return Qtrue;
}
return Qfalse;
}
keys → array Show source
返回光纤局部变量的名称数组(作为符号)。
thr = Thread.new do
Thread.current[:cat] = 'meow'
Thread.current["dog"] = 'woof'
end
thr.join #=> #<Thread:0x401b3f10 dead>
thr.keys #=> [:dog, :cat]
static VALUE
rb_thread_keys(VALUE self)
{
rb_thread_t *th;
VALUE ary = rb_ary_new(
GetThreadPtr(self, th
if (th->local_storage) {
st_foreach(th->local_storage, thread_keys_i, ary
}
return ary;
}
exit → thr or nil Show source
kill → thr or nil
terminate → thr or nil
终止thr
并安排另一个线程运行。
如果此线程已被标记为被杀死,则退出返回线程。
如果这是主线程或最后一个线程,则退出该过程。
VALUE
rb_thread_kill(VALUE thread)
{
rb_thread_t *th;
GetThreadPtr(thread, th
if (th->to_kill || th->status == THREAD_KILLED) {
return thread;
}
if (th == th->vm->main_thread) {
rb_exit(EXIT_SUCCESS
}
thread_debug("rb_thread_kill: %p (%"PRI_THREAD_ID")\n", (void *)th, thread_id_str(th)
if (th == GET_THREAD()) {
/* kill myself immediately */
rb_threadptr_to_kill(th
}
else {
threadptr_check_pending_interrupt_queue(th
rb_threadptr_pending_interrupt_enque(th, eKillSignal
rb_threadptr_interrupt(th
}
return thread;
}
name → string Show source
显示线程的名称。
static VALUE
rb_thread_getname(VALUE thread)
{
rb_thread_t *th;
GetThreadPtr(thread, th
return th->name;
}
name=(name) → string Show source
设置给定的红宝石线程的名称。在某些平台上,它可能会将名称设置为pthread和/或内核。
static VALUE
rb_thread_setname(VALUE thread, VALUE name)
{
#ifdef SET_ANOTHER_THREAD_NAME
const char *s = "";
#endif
rb_thread_t *th;
GetThreadPtr(thread, th
if (!NIL_P(name)) {
rb_encoding *enc;
StringValueCStr(name
enc = rb_enc_get(name
if (!rb_enc_asciicompat(enc)) {
rb_raise(rb_eArgError, "ASCII incompatible encoding (%s)",
rb_enc_name(enc)
}
name = rb_str_new_frozen(name
#ifdef SET_ANOTHER_THREAD_NAME
s = RSTRING_PTR(name
#endif
}
th->name = name;
#if defined(SET_ANOTHER_THREAD_NAME)
if (threadptr_initialized(th)) {
SET_ANOTHER_THREAD_NAME(th->thread_id, s
}
#endif
return name;
}
pending_interrupt?(error = nil) → true/false Show source
返回目标线程的异步队列是否为空。
如果error
给出,则仅检查error
类型延迟事件。
看看::pending_interrupt?了解更多信息。
static VALUE
rb_thread_pending_interrupt_p(int argc, VALUE *argv, VALUE target_thread)
{
rb_thread_t *target_th;
GetThreadPtr(target_thread, target_th
if (!target_th->pending_interrupt_queue) {
return Qfalse;
}
if (rb_threadptr_pending_interrupt_empty_p(target_th)) {
return Qfalse;
}
else {
if (argc == 1) {
VALUE err;
rb_scan_args(argc, argv, "01", &err
if (!rb_obj_is_kind_of(err, rb_cModule)) {
rb_raise(rb_eTypeError, "class or module required for rescue clause"
}
if (rb_threadptr_pending_interrupt_include_p(target_th, err)) {
return Qtrue;
}
else {
return Qfalse;
}
}
return Qtrue;
}
}
priority → integer Show source
返回thr
的优先级。默认值是从创建新线程的当前线程继承的,或者是初始主线程的零; 较高优先级的线程将比较低优先级的线程运行更频繁(但较低优先级的线程也可以运行)。
这只是暗示Ruby线程调度器。在某些平台上可能会被忽略。
Thread.current.priority #=> 0
static VALUE
rb_thread_priority(VALUE thread)
{
rb_thread_t *th;
GetThreadPtr(thread, th
return INT2NUM(th->priority
}
priority= integer → thr Show source
将thr
的优先级设置为整数
。优先级较高的线程将比较低优先级的线程运行得更频繁(但优先级较低的线程也可以运行)。
这只是暗示Ruby线程调度器。在某些平台上可能会被忽略。
count1 = count2 = 0
a = Thread.new do
loop { count1 += 1 }
end
a.priority = -1
b = Thread.new do
loop { count2 += 1 }
end
b.priority = -2
sleep 1 #=> 1
count1 #=> 622504
count2 #=> 5832
static VALUE
rb_thread_priority_set(VALUE thread, VALUE prio)
{
rb_thread_t *th;
int priority;
GetThreadPtr(thread, th
#if USE_NATIVE_THREAD_PRIORITY
th->priority = NUM2INT(prio
native_thread_apply_priority(th
#else
priority = NUM2INT(prio
if (priority > RUBY_THREAD_PRIORITY_MAX) {
priority = RUBY_THREAD_PRIORITY_MAX;
}
else if (priority < RUBY_THREAD_PRIORITY_MIN) {
priority = RUBY_THREAD_PRIORITY_MIN;
}
th->priority = priority;
#endif
return INT2NUM(th->priority
}
raise Show source
raise(string)
raise(exception [, string , array])
引发给定线程的异常。来电者不一定是thr
。请参阅Kernel#raise以获取更多信息。
Thread.abort_on_exception = true
a = Thread.new { sleep(200) }
a.raise("Gotcha")
这将产生:
prog.rb:3: Gotcha (RuntimeError)
from prog.rb:2:in `initialize'
from prog.rb:2:in `new'
from prog.rb:2
static VALUE
thread_raise_m(int argc, VALUE *argv, VALUE self)
{
rb_thread_t *target_th;
rb_thread_t *th = GET_THREAD(
GetThreadPtr(self, target_th
threadptr_check_pending_interrupt_queue(target_th
rb_threadptr_raise(target_th, argc, argv
/* To perform Thread.current.raise as Kernel.raise */
if (th == target_th) {
RUBY_VM_CHECK_INTS(th
}
return Qnil;
}
report_on_exception → true or false Show source
返回线程本地“report on exception”条件的状态thr
。
默认是false
。
另请参阅report_on_exception =。
还有一个类级别的方法可以为所有线程设置它,请参阅::report_on_exception。
static VALUE
rb_thread_report_exc(VALUE thread)
{
rb_thread_t *th;
GetThreadPtr(thread, th
return th->report_on_exception ? Qtrue : Qfalse;
}
report_on_exception= boolean → true or false Show source
如果设置为true
,则在此引发异常时,所有线程(包括主程序)都将报告异常thr
。
另请参阅report_on_exception。
还有一个类级别的方法可以为所有线程设置它,请参阅:report_on_exception =。
static VALUE
rb_thread_report_exc_set(VALUE thread, VALUE val)
{
rb_thread_t *th;
GetThreadPtr(thread, th
th->report_on_exception = RTEST(val
return val;
}
run → thr Show source
唤醒thr
,使其有资格进行安排。
a = Thread.new { puts "a"; Thread.stop; puts "c" }
sleep 0.1 while a.status!='sleep'
puts "Got here"
a.run
a.join
这将产生:
a
Got here
c
另请参见实例方法唤醒。
VALUE
rb_thread_run(VALUE thread)
{
rb_thread_wakeup(thread
rb_thread_schedule(
return thread;
}
safe_level → integer Show source
返回对thr
有效的安全级别。设置线程本地安全级别可以帮助实施运行不安全代码的沙箱。
thr = Thread.new { $SAFE = 1; sleep }
Thread.current.safe_level #=> 0
thr.safe_level #=> 1
static VALUE
rb_thread_safe_level(VALUE thread)
{
rb_thread_t *th;
GetThreadPtr(thread, th
return INT2NUM(th->safe_level
}
set_trace_func(proc) → proc Show source
set_trace_func(nil) → nil
在thr
上建立proc
作为跟踪处理程序,或者如果参数是nil
禁用跟踪。
请参阅Kernel#set_trace_func。
static VALUE
thread_set_trace_func_m(VALUE obj, VALUE trace)
{
rb_thread_t *th;
GetThreadPtr(obj, th
rb_threadptr_remove_event_hook(th, call_trace_func, Qundef
if (NIL_P(trace)) {
return Qnil;
}
thread_add_trace_func(th, trace
return trace;
}
status → string, false or nil Show source
返回的状态thr
。
"sleep"
如果此线程正在休眠或正在等待I/O,则返回
"run"
当这个线程正在执行
"aborting"
如果此线程正在中止
false
当这个线程正常终止
nil
如果以异常终止。
a = Thread.new { raise("die now") }
b = Thread.new { Thread.stop }
c = Thread.new { Thread.exit }
d = Thread.new { sleep }
d.kill #=> #<Thread:0x401b3678 aborting>
a.status #=> nil
b.status #=> "sleep"
c.status #=> false
d.status #=> "aborting"
Thread.current.status #=> "run"
另请参阅活动的实例方法?并停止?
static VALUE
rb_thread_status(VALUE thread)
{
rb_thread_t *th;
GetThreadPtr(thread, th
if (rb_threadptr_dead(th)) {
if (!NIL_P(th->errinfo) && !FIXNUM_P(th->errinfo)
/* TODO */ ) {
return Qnil;
}
return Qfalse;
}
return rb_str_new2(thread_status_name(th, FALSE)
}
stop? → true or false Show source
返回true
如果thr
已死或睡觉。
a = Thread.new { Thread.stop }
b = Thread.current
a.stop? #=> true
b.stop? #=> false
另见alive? 和状态。
static VALUE
rb_thread_stop_p(VALUE thread)
{
rb_thread_t *th;
GetThreadPtr(thread, th
if (rb_threadptr_dead(th))
return Qtrue;
if (th->status == THREAD_STOPPED || th->status == THREAD_STOPPED_FOREVER)
return Qtrue;
return Qfalse;
}
terminate → thr or nil Show source
终止thr
并安排另一个线程运行。
如果此线程已被标记为被杀死,则退出返回线程。
如果这是主线程或最后一个线程,则退出该过程。
VALUE
rb_thread_kill(VALUE thread)
{
rb_thread_t *th;
GetThreadPtr(thread, th
if (th->to_kill || th->status == THREAD_KILLED) {
return thread;
}
if (th == th->vm->main_thread) {
rb_exit(EXIT_SUCCESS
}
thread_debug("rb_thread_kill: %p (%"PRI_THREAD_ID")\n", (void *)th, thread_id_str(th)
if (th == GET_THREAD()) {
/* kill myself immediately */
rb_threadptr_to_kill(th
}
else {
threadptr_check_pending_interrupt_queue(th
rb_threadptr_pending_interrupt_enque(th, eKillSignal
rb_threadptr_interrupt(th
}
return thread;
}
thread_variable?(key) → true or false Show source
如果给定的字符串(或符号)作为线程局部变量存在,则返回true
。
me = Thread.current
me.thread_variable_set(:oliver, "a")
me.thread_variable?(:oliver) #=> true
me.thread_variable?(:stanley) #=> false
请注意,这些不是光纤局部变量。有关更多详细信息,请参阅#[]和#thread_variable_get。
static VALUE
rb_thread_variable_p(VALUE thread, VALUE key)
{
VALUE locals;
ID id = rb_check_id(&key
if (!id) return Qfalse;
locals = rb_ivar_get(thread, id_locals
if (!RHASH(locals)->ntbl)
return Qfalse;
if (st_lookup(RHASH(locals)->ntbl, ID2SYM(id), 0)) {
return Qtrue;
}
return Qfalse;
}
thread_variable_get(key) → obj or nil Show source
返回已设置的线程局部变量的值。请注意,这些与光纤本地值不同。有关光纤本地值,请参阅#[]和#[] =。
线程本地值与线程一起携带,并且不重视光纤。例如:
Thread.new {
Thread.current.thread_variable_set("foo", "bar") # set a thread local
Thread.current["foo"] = "bar" # set a fiber local
Fiber.new {
Fiber.yield [
Thread.current.thread_variable_get("foo"), # get the thread local
Thread.current["foo"], # get the fiber local
]
}.resume
}.join.value # => ['bar', nil]
线程本地返回值“bar”,其中返回nil作为本地光纤。光纤在同一个线程中执行,因此线程本地值可用。
static VALUE
rb_thread_variable_get(VALUE thread, VALUE key)
{
VALUE locals;
locals = rb_ivar_get(thread, id_locals
return rb_hash_aref(locals, rb_to_symbol(key)
}
thread_variable_set(key, value) Show source
使用key
to 设置本地线程value
。请注意,这些线程是本地的,而不是光纤。有关更多信息,请参阅#thread_variable_get和#[]。
static VALUE
rb_thread_variable_set(VALUE thread, VALUE id, VALUE val)
{
VALUE locals;
if (OBJ_FROZEN(thread)) {
rb_error_frozen("thread locals"
}
locals = rb_ivar_get(thread, id_locals
return rb_hash_aset(locals, rb_to_symbol(id), val
}
thread_variables → array Show source
返回线程局部变量的名称数组(作为符号)。
thr = Thread.new do
Thread.current.thread_variable_set(:cat, 'meow')
Thread.current.thread_variable_set("dog", 'woof')
end
thr.join #=> #<Thread:0x401b3f10 dead>
thr.thread_variables #=> [:dog, :cat]
请注意,这些不是光纤局部变量。有关更多详细信息,请参阅#[]和#thread_variable_get。
static VALUE
rb_thread_variables(VALUE thread)
{
VALUE locals;
VALUE ary;
locals = rb_ivar_get(thread, id_locals
ary = rb_ary_new(
rb_hash_foreach(locals, keys_i, ary
return ary;
}
value → obj Show source
等待thr
使用join完成并返回其值,或引发终止线程的异常。
a = Thread.new { 2 + 2 }
a.value #=> 4
b = Thread.new { raise 'something went wrong' }
b.value #=> RuntimeError: something went wrong
static VALUE
thread_value(VALUE self)
{
rb_thread_t *th;
GetThreadPtr(self, th
thread_join(th, DELAY_INFTY
return th->value;
}
wakeup → thr Show source
将给定的线程标记为符合调度的条件,但它仍可能在I/O上保持阻塞状态。
注意:
这不会调用调度程序,请参阅run以获取更多信息。
c = Thread.new { Thread.stop; puts "hey!" }
sleep 0.1 while c.status!='sleep'
c.wakeup
c.join
#=> "hey!"
VALUE
rb_thread_wakeup(VALUE thread)
{
if (!RTEST(rb_thread_wakeup_alive(thread))) {
rb_raise(rb_eThreadError, "killed thread"
}
return thread;
}