Class: Thread

Inherits:
Object show all
Defined in:
vm.c

Overview

Thread encapsulates the behavior of a thread of execution, including the main thread of the Ruby script.

In the descriptions of the methods in this class, the parameter sym refers to a symbol, which is either a quoted string or a Symbol (such as :name).

Defined Under Namespace

Classes: Backtrace

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initializeObject

:nodoc:


661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
# File 'thread.c', line 661

static VALUE
thread_initialize(VALUE thread, VALUE args)
{
    rb_thread_t *th;
    if (!rb_block_given_p()) {
	rb_raise(rb_eThreadError, "must be called with a block");
    }
    GetThreadPtr(thread, th);
    if (th->first_args) {
	VALUE proc = th->first_proc, line, loc;
	const char *file;
        if (!proc || !RTEST(loc = rb_proc_location(proc))) {
            rb_raise(rb_eThreadError, "already initialized thread");
        }
	file = RSTRING_PTR(RARRAY_PTR(loc)[0]);
	if (NIL_P(line = RARRAY_PTR(loc)[1])) {
	    rb_raise(rb_eThreadError, "already initialized thread - %s",
		     file);
	}
        rb_raise(rb_eThreadError, "already initialized thread - %s:%d",
                 file, NUM2INT(line));
    }
    return thread_create_core(thread, args, 0);
}

Class Method Details

.abort_on_exceptionBoolean

Returns the status of the global "abort on exception'' condition. The default is false. When set to true, or if the global $DEBUG flag is true (perhaps because the command line option -d was specified) all threads will abort (the process will exit(0)) if an exception is raised in any thread. See also Thread::abort_on_exception=.

Returns:

  • (Boolean)

2354
2355
2356
2357
2358
# File 'thread.c', line 2354

static VALUE
rb_thread_s_abort_exc(void)
{
    return GET_THREAD()->vm->thread_abort_on_exception ? Qtrue : Qfalse;
}

.abort_on_exception=(boolean) ⇒ Boolean

When set to true, all threads will abort if an exception is raised. Returns the new state.

Thread.abort_on_exception = true
t1 = Thread.new do
  puts  "In new thread"
  raise "Exception from thread"
end
sleep(1)
puts "not reached"

produces:

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

Returns:

  • (Boolean)

2385
2386
2387
2388
2389
2390
2391
# File 'thread.c', line 2385

static VALUE
rb_thread_s_abort_exc_set(VALUE self, VALUE val)
{
    rb_secure(4);
    GET_THREAD()->vm->thread_abort_on_exception = RTEST(val);
    return val;
}

.currentObject

Returns the currently executing thread.

Thread.current   #=> #<Thread:0x401bdf4c run>

2316
2317
2318
2319
2320
# File 'thread.c', line 2316

static VALUE
thread_s_current(VALUE klass)
{
    return rb_thread_current();
}

.DEBUGNumeric

Returns the thread debug level. Available only if compiled with THREAD_DEBUG=-1.

Returns:


171
172
173
174
175
# File 'thread.c', line 171

static VALUE
rb_thread_s_debug(void)
{
    return INT2NUM(rb_thread_debug_enabled);
}

.DEBUG=(num) ⇒ Object

Sets the thread debug level. Available only if compiled with THREAD_DEBUG=-1.


185
186
187
188
189
190
# File 'thread.c', line 185

static VALUE
rb_thread_s_debug_set(VALUE self, VALUE val)
{
    rb_thread_debug_enabled = RTEST(val) ? NUM2INT(val) : 0;
    return val;
}

.exitObject

Terminates the currently running thread and schedules another thread to be run. If this thread is already marked to be killed, exit returns the Thread. If this is the main thread, or the last thread, exit the process.


2146
2147
2148
2149
2150
2151
# File 'thread.c', line 2146

static VALUE
rb_thread_exit(void)
{
    rb_thread_t *th = GET_THREAD();
    return rb_thread_kill(th->self);
}

.start([args]) {|args| ... } ⇒ Object .fork([args]) {|args| ... } ⇒ Object

Basically the same as Thread::new. However, if class Thread is subclassed, then calling start in that subclass will not invoke the subclass's initialize method.

Overloads:

  • .start([args]) {|args| ... } ⇒ Object

    Yields:

    • (args)
  • .fork([args]) {|args| ... } ⇒ Object

    Yields:

    • (args)

654
655
656
657
658
# File 'thread.c', line 654

static VALUE
thread_start(VALUE klass, VALUE args)
{
    return thread_create_core(rb_thread_alloc(klass), args, 0);
}

.handle_interrupt(hash) { ... } ⇒ Object

Changes asynchronous interrupt timing.

interrupt means asynchronous event and corresponding procedure by Thread#raise, Thread#kill, signal trap (not supported yet) and main thread termination (if main thread terminates, then all other thread will be killed).

The given hash has pairs like ExceptionClass => :TimingSymbol. Where the ExceptionClass is the interrupt handled by the given block. The TimingSymbol can be one of the following symbols:

:immediate

Invoke interrupts immediately.

:on_blocking

Invoke interrupts while BlockingOperation.

:never

Never invoke all interrupts.

BlockingOperation means that the operation will block the calling thread, such as read and write. On CRuby implementation, BlockingOperation is any operation executed without GVL.

Masked asynchronous interrupts are delayed until they are enabled. This method is similar to sigprocmask(3).

NOTE

Asynchronous interrupts are difficult to use.

If you need to communicate between threads, please consider to use another way such as Queue.

Or use them with deep understanding about this method.

Usage

In this example, we can guard from Thread#raise exceptions.

Using the :never TimingSymbol the RuntimeError exception will always be ignored in the first block of the main thread. In the second ::handle_interrupt block we can purposefully handle RuntimeError exceptions.

th = Thread.new do
  Thead.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"

While we are ignoring the RuntimeError exception, it's safe to write our resource allocation code. Then, the ensure block is where we can safely deallocate your resources.

Guarding from TimeoutError

In the next example, we will guard from the TimeoutError exception. This will help prevent from leaking resources when TimeoutError exceptions occur during normal ensure clause. For this example we use the help of the standard library Timeout, from lib/timeout.rb

require 'timeout'
Thread.handle_interrupt(TimeoutError => :never) {
  timeout(10){
    # TimeoutError doesn't occur here
    Thread.handle_interrupt(TimeoutError => :on_blocking) {
      # possible to be killed by TimeoutError
      # while blocking operation
    }
    # TimeoutError doesn't occur here
  }
}

In the first part of the timeout block, we can rely on TimeoutError being ignored. Then in the TimeoutError => :on_blocking block, any operation that will block the calling thread is susceptible to a TimeoutError exception being raised.

Stack control settings

It's possible to stack multiple levels of ::handle_interrupt blocks in order to control more than one ExceptionClass and TimingSymbol at a time.

Thread.handle_interrupt(FooError => :never) {
  Thread.handle_interrupt(BarError => :never) {
     # FooError and BarError are prohibited.
  }
}

Inheritance with ExceptionClass

All exceptions inherited from the ExceptionClass parameter will be considered.

Thread.handle_interrupt(Exception => :never) {
  # all exceptions inherited from Exception are prohibited.
}

Yields:


1690
1691
1692
1693
1694
1695
1696
1697
1698
1699
1700
1701
1702
1703
1704
1705
1706
1707
1708
1709
1710
1711
1712
1713
1714
1715
1716
1717
1718
1719
1720
1721
1722
1723
1724
1725
1726
1727
1728
1729
# File 'thread.c', line 1690

static VALUE
rb_thread_s_handle_interrupt(VALUE self, VALUE mask_arg)
{
    VALUE mask;
    rb_thread_t *th = GET_THREAD();
    VALUE r = Qnil;
    int state;

    if (!rb_block_given_p()) {
	rb_raise(rb_eArgError, "block is needed.");
    }

    mask = rb_convert_type(mask_arg, T_HASH, "Hash", "to_hash");
    rb_hash_foreach(mask, handle_interrupt_arg_check_i, 0);
    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) {
	JUMP_TAG(state);
    }

    return r;
}

.kill(thread) ⇒ Object

Causes the given thread to exit (see 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

2129
2130
2131
2132
2133
# File 'thread.c', line 2129

static VALUE
rb_thread_s_kill(VALUE obj, VALUE th)
{
    return rb_thread_kill(th);
}

.listArray

Returns an array of Thread objects for all threads that are either runnable or stopped.

Thread.new { sleep(200) }
Thread.new { 1000000.times {|i| i*i } }
Thread.new { Thread.stop }
Thread.list.each {|t| p t}

produces:

#<Thread:0x401b3e84 sleep>
#<Thread:0x401b3f38 run>
#<Thread:0x401b3fb0 sleep>
#<Thread:0x401bdf4c run>

Returns:


2293
2294
2295
2296
2297
2298
2299
# File 'thread.c', line 2293

VALUE
rb_thread_list(void)
{
    VALUE ary = rb_ary_new();
    st_foreach(GET_THREAD()->vm->living_threads, thread_list_i, ary);
    return ary;
}

.mainObject

Returns the main thread.


2335
2336
2337
2338
2339
# File 'thread.c', line 2335

static VALUE
rb_thread_s_main(VALUE klass)
{
    return rb_thread_main();
}

.newObject

:nodoc:


626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
# File 'thread.c', line 626

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 (!th->first_args) {
	rb_raise(rb_eThreadError, "uninitialized thread - check `%s#initialize'",
		 rb_class2name(klass));
    }
    return thread;
}

.passObject

.pending_interrupt?(error = nil) ⇒ Boolean

Returns whether or not the asynchronous queue is empty.

Since Thread::handle_interrupt can be used to defer asynchronous events. This method can be used to determine if there are any deferred events.

If you find this method returns true, then you may finish :never blocks.

For example, the following method processes deferred asynchronous events immediately.

def Thread.kick_interrupt_immediately
  Thread.handle_interrupt(Object => :immediate) {
    Thread.pass
  }
end

If error is given, then check only for error type deferred events.

Usage

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

This example can also be written as the following, which you should use to avoid asynchronous interrupts.

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

Returns:

  • (Boolean)

1826
1827
1828
1829
1830
# File 'thread.c', line 1826

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);
}

.start([args]) {|args| ... } ⇒ Object .fork([args]) {|args| ... } ⇒ Object

Basically the same as Thread::new. However, if class Thread is subclassed, then calling start in that subclass will not invoke the subclass's initialize method.

Overloads:

  • .start([args]) {|args| ... } ⇒ Object

    Yields:

    • (args)
  • .fork([args]) {|args| ... } ⇒ Object

    Yields:

    • (args)

654
655
656
657
658
# File 'thread.c', line 654

static VALUE
thread_start(VALUE klass, VALUE args)
{
    return thread_create_core(rb_thread_alloc(klass), args, 0);
}

.stopnil

Stops execution of the current thread, putting it into a "sleep'' state, and schedules execution of another thread.

a = Thread.new { print "a"; Thread.stop; print "c" }
sleep 0.1 while a.status!='sleep'
print "b"
a.run
a.join

produces:

abc

Returns:

  • (nil)

2242
2243
2244
2245
2246
2247
2248
2249
2250
2251
# File 'thread.c', line 2242

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;
}

Instance Method Details

#[](sym) ⇒ Object?

Attribute Reference---Returns the value of a fiber-local variable (current thread's root fiber if not explicitely inside a Fiber), using either a symbol or a string name. If the specified variable does not exist, returns 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

produces:

#<Thread:0x00000002a54220 dead>: A
#<Thread:0x00000002a541a8 dead>: B
#<Thread:0x00000002a54130 dead>: C

Thread#[] and Thread#[]= are not thread-local but fiber-local. This confusion did not exist in Ruby 1.8 because fibers were only available since Ruby 1.9. Ruby 1.9 chooses that the methods behaves fiber-local to save following idiom for dynamic scope.

def meth(newvalue)
  begin
    oldvalue = Thread.current[:name]
    Thread.current[:name] = newvalue
    yield
  ensure
    Thread.current[:name] = oldvalue
  end
end

The idiom may not work as dynamic scope if the methods are thread-local and a given block switches fiber.

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.)

For thread-local variables, please see Thread#thread_local_get and Thread#thread_local_set.

Returns:


2693
2694
2695
2696
2697
# File 'thread.c', line 2693

static VALUE
rb_thread_aref(VALUE thread, VALUE id)
{
    return rb_thread_local_aref(thread, rb_to_id(id));
}

#[]=(sym) ⇒ Object

Attribute Assignment---Sets or creates the value of a fiber-local variable, using either a symbol or a string. See also Thread#[]. For thread-local variables, please see Thread#thread_variable_set and Thread#thread_variable_get.

Returns:


2732
2733
2734
2735
2736
# File 'thread.c', line 2732

static VALUE
rb_thread_aset(VALUE self, VALUE id, VALUE val)
{
    return rb_thread_local_aset(self, rb_to_id(id), val);
}

#abort_on_exceptionBoolean

Returns the status of the thread-local "abort on exception'' condition for thr. The default is false. See also Thread::abort_on_exception=.

Returns:

  • (Boolean)

2403
2404
2405
2406
2407
2408
2409
# File 'thread.c', line 2403

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) ⇒ Boolean

When set to true, causes all threads (including the main program) to abort if an exception is raised in thr. The process will effectively exit(0).

Returns:

  • (Boolean)

2421
2422
2423
2424
2425
2426
2427
2428
2429
2430
# File 'thread.c', line 2421

static VALUE
rb_thread_abort_exc_set(VALUE thread, VALUE val)
{
    rb_thread_t *th;
    rb_secure(4);

    GetThreadPtr(thread, th);
    th->abort_on_exception = RTEST(val);
    return val;
}

#alive?Boolean

Returns true if thr is running or sleeping.

thr = Thread.new { }
thr.join                #=> #<Thread:0x401b3fb0 dead>
Thread.current.alive?   #=> true
thr.alive?              #=> false

Returns:

  • (Boolean)

Returns:

  • (Boolean)

2534
2535
2536
2537
2538
2539
2540
2541
2542
2543
# File 'thread.c', line 2534

static VALUE
rb_thread_alive_p(VALUE thread)
{
    rb_thread_t *th;
    GetThreadPtr(thread, th);

    if (rb_threadptr_dead(th))
	return Qfalse;
    return Qtrue;
}

#backtraceArray

Returns the current backtrace of the target thread.

Returns:


4842
4843
4844
4845
4846
# File 'thread.c', line 4842

static VALUE
rb_thread_backtrace_m(int argc, VALUE *argv, VALUE thval)
{
    return vm_thread_backtrace(argc, argv, thval);
}

#backtrace_locations(*args) ⇒ Object

Returns the execution stack for the target thread---an array containing backtrace location objects.

See Thread::Backtrace::Location for more information.

This method behaves similarly to Kernel#caller_locations except it applies to a specific thread.


4859
4860
4861
4862
4863
# File 'thread.c', line 4859

static VALUE
rb_thread_backtrace_locations_m(int argc, VALUE *argv, VALUE thval)
{
    return vm_thread_backtrace_locations(argc, argv, thval);
}

#exitnil #killnil #terminatenil

Terminates thr and schedules another thread to be run. If this thread is already marked to be killed, exit returns the Thread. If this is the main thread, or the last thread, exits the process.

Overloads:

  • #exitnil

    Returns:

    • (nil)
  • #killnil

    Returns:

    • (nil)
  • #terminatenil

    Returns:

    • (nil)

2084
2085
2086
2087
2088
2089
2090
2091
2092
2093
2094
2095
2096
2097
2098
2099
2100
2101
2102
2103
2104
2105
2106
2107
2108
2109
2110
2111
2112
# File 'thread.c', line 2084

VALUE
rb_thread_kill(VALUE thread)
{
    rb_thread_t *th;

    GetThreadPtr(thread, th);

    if (th != GET_THREAD() && th->safe_level < 4) {
	rb_secure(4);
    }
    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 (%p)\n", (void *)th, (void *)th->thread_id);

    if (th == GET_THREAD()) {
	/* kill myself immediately */
	rb_threadptr_to_kill(th);
    }
    else {
	rb_threadptr_pending_interrupt_enque(th, eKillSignal);
	rb_threadptr_interrupt(th);
    }
    return thread;
}

#groupnil

Returns the ThreadGroup which contains thr, or nil if the thread is not a member of any group.

Thread.main.group   #=> #<ThreadGroup:0x4029d914>

Returns:

  • (nil)

2443
2444
2445
2446
2447
2448
2449
2450
2451
2452
2453
2454
2455
# File 'thread.c', line 2443

VALUE
rb_thread_group(VALUE thread)
{
    rb_thread_t *th;
    VALUE group;
    GetThreadPtr(thread, th);
    group = th->thgroup;

    if (!group) {
	group = Qnil;
    }
    return group;
}

#inspectString

Dump the name, id, and status of thr to a string.

Returns:


2598
2599
2600
2601
2602
2603
2604
2605
2606
2607
2608
2609
2610
2611
2612
# File 'thread.c', line 2598

static VALUE
rb_thread_inspect(VALUE thread)
{
    const char *cname = rb_obj_classname(thread);
    rb_thread_t *th;
    const char *status;
    VALUE str;

    GetThreadPtr(thread, th);
    status = thread_status_name(th);
    str = rb_sprintf("#<%s:%p %s>", cname, (void *)thread, status);
    OBJ_INFECT(str, thread);

    return str;
}

#joinObject #join(limit) ⇒ Object

The calling thread will suspend execution and run thr. Does not return until thr exits or until limit seconds have passed. If the time limit expires, nil will be returned, otherwise thr is returned.

Any threads not joined will be killed when the main program exits. If thr had previously raised an exception and the abort_on_exception and $DEBUG flags are not set (so the exception has not yet been processed) it will be processed at this time.

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 x thread finish, a will be killed on exit.

produces:

axyz

The following example illustrates the limit parameter.

y = Thread.new { 4.times { sleep 0.1; puts 'tick... ' }}
puts "Waiting" until y.join(0.15)

produces:

tick...
Waiting
tick...
Waitingtick...

tick...

841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
# File 'thread.c', line 841

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) ⇒ Boolean

Returns true if the given string (or symbol) exists as a fiber-local variable.

me = Thread.current
me[:oliver] = "a"
me.key?(:oliver)    #=> true
me.key?(:stanley)   #=> false

Returns:

  • (Boolean)

Returns:

  • (Boolean)

2825
2826
2827
2828
2829
2830
2831
2832
2833
2834
2835
2836
2837
2838
2839
2840
# File 'thread.c', line 2825

static VALUE
rb_thread_key_p(VALUE self, VALUE key)
{
    rb_thread_t *th;
    ID id = rb_to_id(key);

    GetThreadPtr(self, th);

    if (!th->local_storage) {
	return Qfalse;
    }
    if (st_lookup(th->local_storage, id, 0)) {
	return Qtrue;
    }
    return Qfalse;
}

#keysArray

Returns an an array of the names of the fiber-local variables (as Symbols).

thr = Thread.new do
  Thread.current[:cat] = 'meow'
  Thread.current["dog"] = 'woof'
end
thr.join   #=> #<Thread:0x401b3f10 dead>
thr.keys   #=> [:dog, :cat]

Returns:


2880
2881
2882
2883
2884
2885
2886
2887
2888
2889
2890
2891
# File 'thread.c', line 2880

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;
}

#exitnil #killnil #terminatenil

Terminates thr and schedules another thread to be run. If this thread is already marked to be killed, exit returns the Thread. If this is the main thread, or the last thread, exits the process.

Overloads:

  • #exitnil

    Returns:

    • (nil)
  • #killnil

    Returns:

    • (nil)
  • #terminatenil

    Returns:

    • (nil)

2084
2085
2086
2087
2088
2089
2090
2091
2092
2093
2094
2095
2096
2097
2098
2099
2100
2101
2102
2103
2104
2105
2106
2107
2108
2109
2110
2111
2112
# File 'thread.c', line 2084

VALUE
rb_thread_kill(VALUE thread)
{
    rb_thread_t *th;

    GetThreadPtr(thread, th);

    if (th != GET_THREAD() && th->safe_level < 4) {
	rb_secure(4);
    }
    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 (%p)\n", (void *)th, (void *)th->thread_id);

    if (th == GET_THREAD()) {
	/* kill myself immediately */
	rb_threadptr_to_kill(th);
    }
    else {
	rb_threadptr_pending_interrupt_enque(th, eKillSignal);
	rb_threadptr_interrupt(th);
    }
    return thread;
}

#pending_interrupt?(error = nil) ⇒ Boolean

Returns whether or not the asychronous queue is empty for the target thread.

If error is given, then check only for error type deferred events.

See ::pending_interrupt? for more information.

Returns:

  • (Boolean)

1741
1742
1743
1744
1745
1746
1747
1748
1749
1750
1751
1752
1753
1754
1755
1756
1757
1758
1759
1760
1761
1762
1763
1764
1765
1766
1767
# File 'thread.c', line 1741

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 (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;
    }
}

#priorityInteger

Returns the priority of thr. Default is inherited from the current thread which creating the new thread, or zero for the initial main thread; higher-priority thread will run more frequently than lower-priority threads (but lower-priority threads can also run).

This is just hint for Ruby thread scheduler. It may be ignored on some platform.

Thread.current.priority   #=> 0

Returns:


2978
2979
2980
2981
2982
2983
2984
# File 'thread.c', line 2978

static VALUE
rb_thread_priority(VALUE thread)
{
    rb_thread_t *th;
    GetThreadPtr(thread, th);
    return INT2NUM(th->priority);
}

#priority=(integer) ⇒ Object

Sets the priority of thr to integer. Higher-priority threads will run more frequently than lower-priority threads (but lower-priority threads can also run).

This is just hint for Ruby thread scheduler. It may be ignored on some platform.

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

3013
3014
3015
3016
3017
3018
3019
3020
3021
3022
3023
3024
3025
3026
3027
3028
3029
3030
3031
3032
3033
3034
3035
3036
# File 'thread.c', line 3013

static VALUE
rb_thread_priority_set(VALUE thread, VALUE prio)
{
    rb_thread_t *th;
    int priority;
    GetThreadPtr(thread, th);

    rb_secure(4);

#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);
}

#raiseObject #raise(string) ⇒ Object #raise(exception[, string [, array]]) ⇒ Object

Raises an exception (see Kernel::raise) from thr. The caller does not have to be thr.

Thread.abort_on_exception = true
a = Thread.new { sleep(200) }
a.raise("Gotcha")

produces:

prog.rb:3: Gotcha (RuntimeError)
	from prog.rb:2:in `initialize'
	from prog.rb:2:in `new'
	from prog.rb:2

2056
2057
2058
2059
2060
2061
2062
2063
2064
2065
2066
2067
2068
2069
# File 'thread.c', line 2056

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);
    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;
}

#runObject

Wakes up thr, making it eligible for scheduling.

a = Thread.new { puts "a"; Thread.stop; puts "c" }
sleep 0.1 while a.status!='sleep'
puts "Got here"
a.run
a.join

produces:

a
Got here
c

2215
2216
2217
2218
2219
2220
2221
# File 'thread.c', line 2215

VALUE
rb_thread_run(VALUE thread)
{
    rb_thread_wakeup(thread);
    rb_thread_schedule();
    return thread;
}

#safe_levelInteger

Returns the safe level in effect for thr. Setting thread-local safe levels can help when implementing sandboxes which run insecure code.

thr = Thread.new { $SAFE = 3; sleep }
Thread.current.safe_level   #=> 0
thr.safe_level              #=> 3

Returns:


2582
2583
2584
2585
2586
2587
2588
2589
# File 'thread.c', line 2582

static VALUE
rb_thread_safe_level(VALUE thread)
{
    rb_thread_t *th;
    GetThreadPtr(thread, th);

    return INT2NUM(th->safe_level);
}

#statusString, ...

Returns the status of thr: "sleep'' if thr is sleeping or waiting on I/O, "run'' if thr is executing, "aborting'' if thr is aborting, false if thr terminated normally, and nil if thr terminated with an exception.

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"

Returns:


2505
2506
2507
2508
2509
2510
2511
2512
2513
2514
2515
2516
2517
2518
2519
# File 'thread.c', line 2505

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));
}

#stop?Boolean

Returns true if thr is dead or sleeping.

a = Thread.new { Thread.stop }
b = Thread.current
a.stop?   #=> true
b.stop?   #=> false

Returns:

  • (Boolean)

Returns:

  • (Boolean)

2557
2558
2559
2560
2561
2562
2563
2564
2565
2566
2567
2568
# File 'thread.c', line 2557

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;
}

#exitnil #killnil #terminatenil

Terminates thr and schedules another thread to be run. If this thread is already marked to be killed, exit returns the Thread. If this is the main thread, or the last thread, exits the process.

Overloads:

  • #exitnil

    Returns:

    • (nil)
  • #killnil

    Returns:

    • (nil)
  • #terminatenil

    Returns:

    • (nil)

2084
2085
2086
2087
2088
2089
2090
2091
2092
2093
2094
2095
2096
2097
2098
2099
2100
2101
2102
2103
2104
2105
2106
2107
2108
2109
2110
2111
2112
# File 'thread.c', line 2084

VALUE
rb_thread_kill(VALUE thread)
{
    rb_thread_t *th;

    GetThreadPtr(thread, th);

    if (th != GET_THREAD() && th->safe_level < 4) {
	rb_secure(4);
    }
    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 (%p)\n", (void *)th, (void *)th->thread_id);

    if (th == GET_THREAD()) {
	/* kill myself immediately */
	rb_threadptr_to_kill(th);
    }
    else {
	rb_threadptr_pending_interrupt_enque(th, eKillSignal);
	rb_threadptr_interrupt(th);
    }
    return thread;
}

#thread_variable?(key) ⇒ Boolean

Returns true if the given string (or symbol) exists as a thread-local variable.

me = Thread.current
me.thread_variable_set(:oliver, "a")
me.thread_variable?(:oliver)    #=> true
me.thread_variable?(:stanley)   #=> false

Note that these are not fiber local variables. Please see Thread#[] and Thread#thread_variable_get for more details.

Returns:

  • (Boolean)

Returns:

  • (Boolean)

2946
2947
2948
2949
2950
2951
2952
2953
2954
2955
2956
2957
2958
2959
2960
2961
# File 'thread.c', line 2946

static VALUE
rb_thread_variable_p(VALUE thread, VALUE key)
{
    VALUE locals;

    locals = rb_iv_get(thread, "locals");

    if (!RHASH(locals)->ntbl)
        return Qfalse;

    if (st_lookup(RHASH(locals)->ntbl, ID2SYM(rb_to_id(key)), 0)) {
	return Qtrue;
    }

    return Qfalse;
}

#thread_variable_get(key) ⇒ Object?

Returns the value of a thread local variable that has been set. Note that these are different than fiber local values. For fiber local values, please see Thread#[] and Thread#[]=.

Thread local values are carried along with threads, and do not respect fibers. For example:

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]

The value "bar" is returned for the thread local, where nil is returned for the fiber local. The fiber is executed in the same thread, so the thread local values are available.

See also Thread#[]

Returns:


2768
2769
2770
2771
2772
2773
2774
2775
2776
2777
2778
2779
2780
2781
2782
# File 'thread.c', line 2768

static VALUE
rb_thread_variable_get(VALUE thread, VALUE id)
{
    VALUE locals;
    rb_thread_t *th;

    GetThreadPtr(thread, th);

    if (rb_safe_level() >= 4 && th != GET_THREAD()) {
	rb_raise(rb_eSecurityError, "Insecure: can't modify thread locals");
    }

    locals = rb_iv_get(thread, "locals");
    return rb_hash_aref(locals, ID2SYM(rb_to_id(id)));
}

#thread_variable_set(key, value) ⇒ Object

Sets a thread local with key to value. Note that these are local to threads, and not to fibers. Please see Thread#thread_variable_get and Thread#[] for more information.


2793
2794
2795
2796
2797
2798
2799
2800
2801
2802
2803
2804
2805
2806
2807
2808
2809
2810
# File 'thread.c', line 2793

static VALUE
rb_thread_variable_set(VALUE thread, VALUE id, VALUE val)
{
    VALUE locals;
    rb_thread_t *th;

    GetThreadPtr(thread, th);

    if (rb_safe_level() >= 4 && th != GET_THREAD()) {
	rb_raise(rb_eSecurityError, "Insecure: can't modify thread locals");
    }
    if (OBJ_FROZEN(thread)) {
	rb_error_frozen("thread locals");
    }

    locals = rb_iv_get(thread, "locals");
    return rb_hash_aset(locals, ID2SYM(rb_to_id(id)), val);
}

#thread_variablesArray

Returns an an array of the names of the thread-local variables (as Symbols).

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]

Note that these are not fiber local variables. Please see Thread#[] and Thread#thread_variable_get for more details.

Returns:


2917
2918
2919
2920
2921
2922
2923
2924
2925
2926
2927
2928
# File 'thread.c', line 2917

static VALUE
rb_thread_variables(VALUE thread)
{
    VALUE locals;
    VALUE ary;

    locals = rb_iv_get(thread, "locals");
    ary = rb_ary_new();
    rb_hash_foreach(locals, keys_i, ary);

    return ary;
}

#valueObject

Waits for thr to complete (via Thread#join) and returns its value.

a = Thread.new { 2 + 2 }
a.value   #=> 4

Returns:


869
870
871
872
873
874
875
876
# File 'thread.c', line 869

static VALUE
thread_value(VALUE self)
{
    rb_thread_t *th;
    GetThreadPtr(self, th);
    thread_join(th, DELAY_INFTY);
    return th->value;
}

#wakeupObject

Marks thr as eligible for scheduling (it may still remain blocked on I/O, however). Does not invoke the scheduler (see Thread#run).

c = Thread.new { Thread.stop; puts "hey!" }
sleep 0.1 while c.status!='sleep'
c.wakeup
c.join

produces:

hey!

2171
2172
2173
2174
2175
2176
2177
2178
# File 'thread.c', line 2171

VALUE
rb_thread_wakeup(VALUE thread)
{
    if (!RTEST(rb_thread_wakeup_alive(thread))) {
	rb_raise(rb_eThreadError, "killed thread");
    }
    return thread;
}