非常教程

Ruby 2.4参考手册

线 | Thread

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异常。

使用:neverTimingSymbol时,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

使用keyto 设置本地线程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;
}
Ruby 2.4

Ruby 是一种面向对象、命令式、函数式、动态的通用编程语言,是世界上最优美而巧妙的语言。

主页 https://www.ruby-lang.org/
源码 https://github.com/ruby/ruby
版本 2.4
发布版本 2.4.1

Ruby 2.4目录

1.缩略 | Abbrev
2.ARGF
3.数组 | Array
4.Base64
5.基本对象 | BasicObject
6.基准测试 | Benchmark
7.BigDecimal
8.绑定 | Binding
9.CGI
10.类 | Class
11.比较 | Comparable
12.负责 | Complex
13.计算续体 | Continuation
14.覆盖 | Coverage
15.CSV
16.日期 | Date
17.日期时间 | DateTime
18.DBM
19.代理 | Delegator
20.摘要 | Digest
21.Dir
22.DRb
23.编码 | Encoding
24.枚举 | Enumerable
25.枚举 | Enumerator
26.ENV
27.ERB
28.错误 | Errors
29.Etc
30.期望值 | Exception
31.错误类 | FalseClass
32.Fiber
33.Fiddle
34.文件 | File
35.文件实用程序 | FileUtils
36.查找 | Find
37.浮点 | Float
38.Forwardable
39.GC
40.GDBM
41.GetoptLong
42.Hash
43.Integer
44.IO
45.IPAddr
46.JSON
47.Kernel
48.语言 | 3Language
49.记录 | Logger
50.编排 | Marshal
51.MatchData
52.数学 | Math
53.矩阵 | Matrix
54.方法 | Method
55.模型 | Module
56.监控 | Monitor
57. 互斥 | Mutex
58.Net
59.Net::FTP
60.Net::HTTP
61.Net::IMAP
62.Net::SMTP
63.NilClass
64.数字 | Numeric
65.对象 | Object
66.ObjectSpace
67.Observable
68.Open3
69.OpenSSL
70.OpenStruct
71.OpenURI
72.OptionParser
73.路径名 | Pathname
74.完整输出 | PrettyPrint
75.Prime
76.Proc
77.过程 | Process
78.PStore
79.PTY
80.队列 | Queue
81.随机 | Random
82.范围 | Range
83.合理的 | Rational
84.Readline
85.Regexp
86.Resolv
87.Ripper
88.RubyVM
89.Scanf
90.SDBM
91.SecureRandom
92.Set
93.Shell
94.信号 | Signal
95.Singleton
96.套接字 | Socket
97.字符串 | String
98.StringIO
99.StringScanner
100.结构 | Struct