Class: Thread
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
-
.abort_on_exception ⇒ Boolean
Returns the status of the global "abort on exception" condition.
-
.abort_on_exception=(boolean) ⇒ Boolean
When set to
true
, all threads will abort if an exception is raised. -
.current ⇒ Object
Returns the currently executing thread.
-
.DEBUG ⇒ Numeric
Returns the thread debug level.
-
.DEBUG=(num) ⇒ Object
Sets the thread debug level.
-
.exit ⇒ Object
Terminates the currently running thread and schedules another thread to be run.
-
.fork ⇒ Object
Basically the same as
Thread::new
. -
.handle_interrupt(hash) { ... } ⇒ Object
Changes asynchronous interrupt timing.
-
.kill(thread) ⇒ Object
Causes the given thread to exit (see
Thread::exit
). -
.list ⇒ Array
Returns an array of
Thread
objects for all threads that are either runnable or stopped. -
.main ⇒ Object
Returns the main thread.
-
.new ⇒ Object
:nodoc:.
- .pass ⇒ Object
-
.pending_interrupt?(error = nil) ⇒ Boolean
Returns whether or not the asynchronous queue is empty.
-
.start ⇒ Object
Basically the same as
Thread::new
. -
.stop ⇒ nil
Stops execution of the current thread, putting it into a "sleep" state, and schedules execution of another thread.
Instance Method Summary collapse
-
#[](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.
-
#[]=(sym) ⇒ Object
Attribute Assignment---Sets or creates the value of a fiber-local variable, using either a symbol or a string.
-
#abort_on_exception ⇒ Boolean
Returns the status of the thread-local "abort on exception" condition for thr.
-
#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. -
#alive? ⇒ Boolean
Returns
true
if thr is running or sleeping. -
#backtrace ⇒ Array
Returns the current backtrace of the target thread.
-
#backtrace_locations(*args) ⇒ Object
Returns the execution stack for the target thread---an array containing backtrace location objects.
-
#exit ⇒ Object
Terminates thr and schedules another thread to be run.
-
#group ⇒ nil
Returns the
ThreadGroup
which contains thr, or nil if the thread is not a member of any group. -
#initialize ⇒ Object
constructor
:nodoc:.
-
#inspect ⇒ String
Dump the name, id, and status of thr to a string.
-
#join ⇒ Object
The calling thread will suspend execution and run thr.
-
#key?(sym) ⇒ Boolean
Returns
true
if the given string (or symbol) exists as a fiber-local variable. -
#keys ⇒ Array
Returns an an array of the names of the fiber-local variables (as Symbols).
-
#kill ⇒ Object
Terminates thr and schedules another thread to be run.
-
#pending_interrupt?(error = nil) ⇒ Boolean
Returns whether or not the asychronous queue is empty for the target thread.
-
#priority ⇒ Integer
Returns the priority of thr.
-
#priority=(integer) ⇒ Object
Sets the priority of thr to integer.
-
#raise ⇒ Object
Raises an exception (see
Kernel::raise
) from thr. -
#run ⇒ Object
Wakes up thr, making it eligible for scheduling.
-
#safe_level ⇒ Integer
Returns the safe level in effect for thr.
-
#status ⇒ String, ...
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, andnil
if thr terminated with an exception. -
#stop? ⇒ Boolean
Returns
true
if thr is dead or sleeping. -
#terminate ⇒ Object
Terminates thr and schedules another thread to be run.
-
#thread_variable?(key) ⇒ Boolean
Returns
true
if the given string (or symbol) exists as a thread-local variable. -
#thread_variable_get(key) ⇒ Object?
Returns the value of a thread local variable that has been set.
-
#thread_variable_set(key, value) ⇒ Object
Sets a thread local with
key
tovalue
. -
#thread_variables ⇒ Array
Returns an an array of the names of the thread-local variables (as Symbols).
-
#value ⇒ Object
Waits for thr to complete (via
Thread#join
) and returns its value. -
#wakeup ⇒ Object
Marks thr as eligible for scheduling (it may still remain blocked on I/O, however).
Constructor Details
#initialize ⇒ Object
: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_exception ⇒ Boolean
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=
.
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
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;
}
|
.current ⇒ Object
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();
}
|
.DEBUG ⇒ Numeric
Returns the thread debug level. Available only if compiled with THREAD_DEBUG=-1.
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;
}
|
.exit ⇒ Object
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.
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.
}
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
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);
}
|
.list ⇒ Array
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>
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;
}
|
.main ⇒ Object
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();
}
|
.new ⇒ Object
: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;
}
|
.pass ⇒ Object
.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
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.
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);
}
|
.stop ⇒ 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
.
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
.
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_exception ⇒ Boolean
Returns the status of the thread-local "abort on exception" condition for thr. The default is false
. See also Thread::abort_on_exception=
.
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)
.
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
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;
}
|
#backtrace ⇒ Array
Returns the current backtrace of the target thread.
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);
}
|
#exit ⇒ nil #kill ⇒ nil #terminate ⇒ nil
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.
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;
}
|
#group ⇒ 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;
}
|
#inspect ⇒ String
Dump the name, id, and status of thr to a string.
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;
}
|
#join ⇒ Object #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
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;
}
|
#keys ⇒ Array
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;
}
|
#exit ⇒ nil #kill ⇒ nil #terminate ⇒ nil
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.
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.
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;
}
}
|
#priority ⇒ Integer
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
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);
}
|
#raise ⇒ Object #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;
}
|
#run ⇒ Object
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_level ⇒ Integer
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);
}
|
#status ⇒ String, ...
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"
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
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;
}
|
#exit ⇒ nil #kill ⇒ nil #terminate ⇒ nil
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.
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.
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#[]
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_variables ⇒ Array
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.
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;
}
|
#value ⇒ Object
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;
}
|
#wakeup ⇒ Object
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;
}
|