Movatterモバイル変換


[0]ホーム

URL:


HomeClassesMethods

In Files

  • thread.c
  • vm.c
  • vm_trace.c

Parent

Object

Namespace

Methods

Files

Class/Module Index[+]

Quicksearch
No matching classes.

Thread

Threads are the Ruby implementation for a concurrent programming model.

Programs that require multiple threads of execution are a perfect candidatefor Ruby'sThread class.

For example, we can create a new thread separate from the main thread'sexecution using::new.

thr =Thread.new {puts"What's the big deal" }

Then we are able to pause the execution of the main thread and allow ournew thread to finish, usingjoin:

thr.join#=> "What's the big deal"

If we don't callthr.join before the main threadterminates, then all other threads includingthr will bekilled.

Alternatively, you can use an array for handling multiple threads at once,like in the following example:

threads = []threads<<Thread.new {puts"What's the big deal" }threads<<Thread.new {3.times {puts"Threads are fun!" } }

After creating a few threads we wait for them all to finish consecutively.

threads.each {|thr|thr.join }

To retrieve the last value of a thread, usevalue

thr =Thread.new {sleep1;"Useful value" }thr.value#=> "Useful value"

Thread initialization

In order to create new threads, Ruby provides::new,::start, and::fork. A block must be provided witheach of these methods, otherwise aThreadError will be raised.

When subclassing theThread class, theinitialize method of your subclass will be ignored by::start and::fork. Otherwise, be sure to callsuper in yourinitialize method.

Thread termination

For terminating threads, Ruby provides a variety of ways to do this.

The class method::kill, is meantto exit a given thread:

thr =Thread.new {sleep }Thread.kill(thr)# sends exit() to thr

Alternatively, you can use the instance methodexit, or any of its aliaseskill orterminate.

thr.exit

Thread status

Ruby provides a few instance methods for querying the state of a giventhread. To get a string with the current thread's state usestatus

thr =Thread.new {sleep }thr.status# => "sleep"thr.exitthr.status# => false

You can also usealive? to tellif the thread is running or sleeping, andstop? if the thread is dead orsleeping.

Thread variables and scope

Since threads are created with blocks, the same rules apply to other Rubyblocks for variable scope. Any local variables created within this blockare accessible to only this thread.

Fiber-local vs. Thread-local

Each fiber has its own bucket for#[] storage. When you set a newfiber-local it is only accessible within thisFiber. To illustrate:

Thread.new {Thread.current[:foo] ="bar"Fiber.new {pThread.current[:foo]# => nil  }.resume}.join

This example uses[] for gettingand[]= for settingfiber-locals, you can also usekeysto list the fiber-locals for a given thread andkey? to check if a fiber-localexists.

When it comes to thread-locals, they are accessible within the entire scopeof the thread. Given the following example:

Thread.new{Thread.current.thread_variable_set(:foo,1)pThread.current.thread_variable_get(:foo)# => 1Fiber.new{Thread.current.thread_variable_set(:foo,2)pThread.current.thread_variable_get(:foo)# => 2  }.resumepThread.current.thread_variable_get(:foo)# => 2}.join

You can see that the thread-local:foo carried over into thefiber and was changed to2 by the end of the thread.

This example makes use ofthread_variable_set tocreate new thread-locals, andthread_variable_get toreference them.

There is alsothread_variables to listall thread-locals, andthread_variable? tocheck if a given thread-local exists.

Exception handling

When an unhandled exception is raised inside a thread, it will terminate.By default, this exception will not propagate to other threads. Theexception is stored and when another thread callsvalue orjoin, the exception will be re-raisedin that thread.

t =Thread.new{raise'something went wrong' }t.value#=> RuntimeError: something went wrong

An exception can be raised from outside the thread using the#raise instance method, which takesthe same parameters asKernel#raise.

Setting::abort_on_exception =true,#abort_on_exception =true, or $DEBUG = true will cause a subsequent unhandled exception raisedin a thread to be automatically re-raised in the main thread.

With the addition of the class method::handle_interrupt, youcan now handle exceptions asynchronously with threads.

Scheduling

Ruby provides a few ways to support scheduling threads in your program.

The first way is by using the class method::stop, to put the current runningthread to sleep and schedule the execution of another thread.

Once a thread is asleep, you can use the instance methodwakeup to mark your thread aseligible for scheduling.

You can also try::pass, whichattempts to pass execution to another thread but is dependent on the OSwhether a running thread will switch or not. The same goes forpriority, which lets you hint tothe thread scheduler which threads you want to take precedence when passingexecution. This method is also dependent on the OS and may be ignored onsome platforms.

Public Class Methods

DEBUG → numclick to toggle source

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

                static VALUErb_thread_s_debug(VALUE _){    return INT2NUM(rb_thread_debug_enabled);}
DEBUG = numclick to toggle source

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

                static VALUErb_thread_s_debug_set(VALUE self, VALUE val){    rb_thread_debug_enabled = RTEST(val) ? NUM2INT(val) : 0;    return val;}
abort_on_exception → true or falseclick to toggle source

Returns the status of the global “abort on exception'' condition.

The default isfalse.

When set totrue, if any thread is aborted by an exception,the raised exception will be re-raised in the main thread.

Can also be specified by the global $DEBUG flag or command line option-d.

See also::abort_on_exception=.

There is also an instance level method to set this for a specific thread,seeabort_on_exception.

                static VALUErb_thread_s_abort_exc(VALUE _){    return GET_THREAD()->vm->thread_abort_on_exception ? Qtrue : Qfalse;}
abort_on_exception= boolean → true or falseclick to toggle source

When set totrue, if any thread is aborted by an exception,the raised exception will be re-raised in the main thread. Returns the newstate.

Thread.abort_on_exception =truet1 =Thread.newdoputs"In new thread"raise"Exception from thread"endsleep(1)puts"not reached"

This will produce:

In new threadprog.rb:4: Exception from thread (RuntimeError) from prog.rb:2:in `initialize' from prog.rb:2:in `new' from prog.rb:2

See also::abort_on_exception.

There is also an instance level method to set this for a specific thread,seeabort_on_exception=.

                static VALUErb_thread_s_abort_exc_set(VALUE self, VALUE val){    GET_THREAD()->vm->thread_abort_on_exception = RTEST(val);    return val;}
current → threadclick to toggle source

Returns the currently executing thread.

Thread.current#=> #<Thread:0x401bdf4c run>
                static VALUEthread_s_current(VALUE klass){    return rb_thread_current();}
exit → threadclick to toggle source

Terminates the currently running thread and schedules another thread to berun.

If this thread is already marked to be killed,::exit returns theThread.

If this is the main thread, or the last thread, exit the process.

                static VALUErb_thread_exit(VALUE _){    rb_thread_t *th = GET_THREAD();    return rb_thread_kill(th->self);}
fork([args]*) {|args| block } → threadclick to toggle source

Basically the same as::new.However, if classThread is subclassed, thencallingstart in that subclass will not invoke thesubclass'sinitialize method.

                static VALUEthread_start(VALUE klass, VALUE args){    struct thread_create_params params = {        .type = thread_invoke_type_proc,        .args = args,        .proc = rb_block_proc(),    };    return thread_create_core(rb_thread_alloc(klass), &params);}
handle_interrupt(hash) { ... } → result of the blockclick to toggle source

Changes asynchronous interrupt timing.

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

The givenhash has pairs likeExceptionClass =>:TimingSymbol. Where the ExceptionClass is the interrupt handled bythe given block. The TimingSymbol can be one of the following symbols:

:immediate

Invoke interrupts immediately.

:on_blocking

Invoke interrupts whileBlockingOperation.

:never

Never invoke all interrupts.

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

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

NOTE

Asynchronous interrupts are difficult to use.

If you need to communicate between threads, please consider to use anotherway such asQueue.

Or use them with deep understanding about this method.

Usage

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

Using the:never TimingSymbol theRuntimeError exception will always be ignoredin the first block of the main thread. In the second::handle_interrupt blockwe can purposefully handleRuntimeErrorexceptions.

th =Thread.newdoThread.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  }endThread.pass# ...th.raise"stop"

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

Guarding from Timeout::Error

In the next example, we will guard from the Timeout::Error exception. Thiswill help prevent from leaking resources when Timeout::Error exceptionsoccur during normal ensure clause. For this example we use the help of thestandard library Timeout, from lib/timeout.rb

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

In the first part of thetimeout block, we can rely onTimeout::Error being ignored. Then in theTimeout::Error =>:on_blocking block, any operation that will block the calling threadis susceptible to a Timeout::Error exception being raised.

Stack control settings

It's possible to stack multiple levels of::handle_interrupt blocksin order to control more than one ExceptionClass and TimingSymbol at atime.

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

Thread.handle_interrupt(Exception => :never) {# all exceptions inherited from Exception are prohibited.}
                static VALUErb_thread_s_handle_interrupt(VALUE self, VALUE mask_arg){    VALUE mask;    rb_execution_context_t * volatile ec = GET_EC();    rb_thread_t * volatile th = rb_ec_thread_ptr(ec);    volatile VALUE r = Qnil;    enum ruby_tag_type state;    if (!rb_block_given_p()) {        rb_raise(rb_eArgError, "block is needed.");    }    mask = 0;    mask_arg = rb_to_hash_type(mask_arg);    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->ec);    }    EC_PUSH_TAG(th->ec);    if ((state = EC_EXEC_TAG()) == TAG_NONE) {        r = rb_yield(Qnil);    }    EC_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->ec);    }    RUBY_VM_CHECK_INTS(th->ec);    if (state) {        EC_JUMP_TAG(th->ec, state);    }    return r;}
ignore_deadlock → true or falseclick to toggle source

Returns the status of the global “ignore deadlock'' condition. Thedefault isfalse, so that deadlock conditions are not ignored.

See also::ignore_deadlock=.

                static VALUErb_thread_s_ignore_deadlock(VALUE _){    return GET_THREAD()->vm->thread_ignore_deadlock ? Qtrue : Qfalse;}
ignore_deadlock = boolean → true or falseclick to toggle source

Returns the new state. When set totrue, the VM will not checkfor deadlock conditions. It is only useful to set this if your applicationcan break a deadlock condition via some other means, such as a signal.

Thread.ignore_deadlock =truequeue =Queue.newtrap(:SIGUSR1){queue.push"Received signal"}# raises fatal error unless ignoring deadlockputsqueue.pop

See also::ignore_deadlock.

                static VALUErb_thread_s_ignore_deadlock_set(VALUE self, VALUE val){    GET_THREAD()->vm->thread_ignore_deadlock = RTEST(val);    return val;}
kill(thread) → threadclick to toggle source

Causes the giventhread to exit, see also::exit.

count =0a =Thread.new {loop {count+=1 } }sleep(0.1)#=> 0Thread.kill(a)#=> #<Thread:0x401b3d30 dead>count#=> 93947a.alive?#=> false
                static VALUErb_thread_s_kill(VALUE obj, VALUE th){    return rb_thread_kill(th);}
list → arrayclick to toggle source

Returns an array ofThread objects for allthreads 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|pt}

This will produce:

#<Thread:0x401b3e84 sleep>#<Thread:0x401b3f38 run>#<Thread:0x401b3fb0 sleep>#<Thread:0x401bdf4c run>
                static VALUEthread_list(VALUE _){    return rb_thread_list();}
main → threadclick to toggle source

Returns the main thread.

                static VALUErb_thread_s_main(VALUE klass){    return rb_thread_main();}
new { ... } → threadclick to toggle source
new(*args, &proc) → thread
new(*args) { |args| ... } → thread

Creates a new thread executing the given block.

Anyargs given to::newwill be passed to the block:

arr = []a,b,c =1,2,3Thread.new(a,b,c) {|d,e,f|arr<<d<<e<<f }.joinarr#=> [1, 2, 3]

AThreadError exception is raised if::new is called without a block.

If you're going to subclassThread, be sureto call super in yourinitialize method, otherwise aThreadError will be raised.

                static VALUEthread_s_new(int argc, VALUE *argv, VALUE klass){    rb_thread_t *th;    VALUE thread = rb_thread_alloc(klass);    if (GET_RACTOR()->threads.main->status == THREAD_KILLED) {        rb_raise(rb_eThreadError, "can't alloc thread");    }    rb_obj_call_init_kw(thread, argc, argv, RB_PASS_CALLED_KEYWORDS);    th = rb_thread_ptr(thread);    if (!threadptr_initialized(th)) {        rb_raise(rb_eThreadError, "uninitialized thread - check `%"PRIsVALUE"#initialize'",                 klass);    }    return thread;}
pass → nilclick to toggle source

Give the thread scheduler a hint to pass execution to another thread. Arunning thread may or may not switch, it depends on OS and processor.

                static VALUEthread_s_pass(VALUE klass){    rb_thread_schedule();    return Qnil;}
pending_interrupt?(error = nil) → true/falseclick to toggle source

Returns whether or not the asynchronous queue is empty.

Since::handle_interrupt can beused to defer asynchronous events, this method can be used to determine ifthere 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 eventsimmediately.

defThread.kick_interrupt_immediatelyThread.handle_interrupt(Object => :immediate) {Thread.pass  }end

Iferror is given, then check only forerror typedeferred 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 toavoid asynchronous interrupts.

flag = trueth = 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 VALUErb_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 falseclick to toggle source

Returns the status of the global “report on exception'' condition.

The default istrue since Ruby 2.5.

All threads created when this flag is true will report a message on $stderrif an exception kills the thread.

Thread.new {1.times {raise } }

will produce this output on $stderr:

#<Thread:...> terminated with exception (report_on_exception is true):Traceback (most recent call last):        2: from -e:1:in `block in <main>'        1: from -e:1:in `times'

This is done to catch errors in threads early. In some cases, you might notwant this output. There are multiple ways to avoid the extra output:

  • If the exception is not intended, the best is to fix the cause of theexception so it does not happen anymore.

  • If the exception is intended, it might be better to rescue it closer towhere it is raised rather then let it kill theThread.

  • If it is guaranteed theThread will be joinedwith#join or#value, then it is safe to disablethis report withThread.current.report_on_exception = falsewhen starting theThread. However, this mighthandle the exception much later, or not at all if theThread is never joined due to the parent threadbeing blocked, etc.

See also::report_on_exception=.

There is also an instance level method to set this for a specific thread,seereport_on_exception=.

                static VALUErb_thread_s_report_exc(VALUE _){    return GET_THREAD()->vm->thread_report_on_exception ? Qtrue : Qfalse;}
report_on_exception= boolean → true or falseclick to toggle source

Returns the new state. When set totrue, all threads createdafterwards will inherit the condition and report a message on $stderr if anexception kills a thread:

Thread.report_on_exception =truet1 =Thread.newdoputs"In new thread"raise"Exception from thread"endsleep(1)puts"In the main thread"

This will produce:

In new thread#<Thread:...prog.rb:2> terminated with exception (report_on_exception is true):Traceback (most recent call last):prog.rb:4:in `block in <main>': Exception from thread (RuntimeError)In the main thread

See also::report_on_exception.

There is also an instance level method to set this for a specific thread,seereport_on_exception=.

                static VALUErb_thread_s_report_exc_set(VALUE self, VALUE val){    GET_THREAD()->vm->thread_report_on_exception = RTEST(val);    return val;}
start([args]*) {|args| block } → threadclick to toggle source

Basically the same as::new.However, if classThread is subclassed, thencallingstart in that subclass will not invoke thesubclass'sinitialize method.

                static VALUEthread_start(VALUE klass, VALUE args){    struct thread_create_params params = {        .type = thread_invoke_type_proc,        .args = args,        .proc = rb_block_proc(),    };    return thread_create_core(rb_thread_alloc(klass), &params);}
stop → nilclick to toggle source

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" }sleep0.1whilea.status!='sleep'print"b"a.runa.join#=> "abc"
                static VALUEthread_stop(VALUE _){    return rb_thread_stop();}

Public Instance Methods

thr[sym] → obj or nilclick to toggle source

Attribute Reference—Returns the value of a fiber-local variable (currentthread's root fiber if not explicitly inside aFiber), using either a symbol or a string name. Ifthe specified variable does not exist, returnsnil.

[Thread.new {Thread.current["name"] ="A" },Thread.new {Thread.current[:name]  ="B" },Thread.new {Thread.current["name"] ="C" }].eachdo|th|th.joinputs"#{th.inspect}: #{th[:name]}"end

This will produce:

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

#[] and#[]= are not thread-local butfiber-local. This confusion did not exist in Ruby 1.8 because fibers areonly available since Ruby 1.9. Ruby 1.9 chooses that the methods behavesfiber-local to save following idiom for dynamic scope.

defmeth(newvalue)beginoldvalue =Thread.current[:name]Thread.current[:name] =newvalueyieldensureThread.current[:name] =oldvalueendend

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

f =Fiber.new {meth(1) {Fiber.yield  }}meth(2) {f.resume}f.resumepThread.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 seethread_variable_get andthread_variable_set.

                static VALUErb_thread_aref(VALUE thread, VALUE key){    ID id = rb_check_id(&key);    if (!id) return Qnil;    return rb_thread_local_aref(thread, id);}
thr[sym] = obj → objclick to toggle source

Attribute Assignment—Sets or creates the value of a fiber-local variable,using either a symbol or a string.

See also#[].

For thread-local variables, please seethread_variable_set andthread_variable_get.

                static VALUErb_thread_aset(VALUE self, VALUE id, VALUE val){    return rb_thread_local_aset(self, rb_to_id(id), val);}
abort_on_exception → true or falseclick to toggle source

Returns the status of the thread-local “abort on exception''condition for thisthr.

The default isfalse.

See alsoabort_on_exception=.

There is also a class level method to set this for all threads, see::abort_on_exception.

                static VALUErb_thread_abort_exc(VALUE thread){    return rb_thread_ptr(thread)->abort_on_exception ? Qtrue : Qfalse;}
abort_on_exception= boolean → true or falseclick to toggle source

When set totrue, if thisthr is aborted by anexception, the raised exception will be re-raised in the main thread.

See alsoabort_on_exception.

There is also a class level method to set this for all threads, see::abort_on_exception=.

                static VALUErb_thread_abort_exc_set(VALUE thread, VALUE val){    rb_thread_ptr(thread)->abort_on_exception = RTEST(val);    return val;}
add_trace_func(proc) → procclick to toggle source

Addsproc as a handler for tracing.

See#set_trace_func andKernel#set_trace_func.

                static VALUEthread_add_trace_func_m(VALUE obj, VALUE trace){    thread_add_trace_func(GET_EC(), rb_thread_ptr(obj), trace);    return trace;}
alive? → true or falseclick to toggle source

Returnstrue ifthr is running or sleeping.

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

See alsostop? andstatus.

                static VALUErb_thread_alive_p(VALUE thread){    if (rb_threadptr_dead(rb_thread_ptr(thread))) {        return Qfalse;    }    else {        return Qtrue;    }}
backtrace → array or nilclick to toggle source

Returns the current backtrace of the target thread.

                static VALUErb_thread_backtrace_m(int argc, VALUE *argv, VALUE thval){    return rb_vm_thread_backtrace(argc, argv, thval);}
backtrace_locations(*args) → array or nilclick to toggle source

Returns the execution stack for the target thread—an array containingbacktrace location objects.

SeeThread::Backtrace::Location formore information.

This method behaves similarly toKernel#caller_locationsexcept it applies to a specific thread.

                static VALUErb_thread_backtrace_locations_m(int argc, VALUE *argv, VALUE thval){    return rb_vm_thread_backtrace_locations(argc, argv, thval);}
exit → thrclick to toggle source
kill → thr
terminate → thr

Terminatesthr and schedules another thread to be run,returning the terminatedThread. If this is themain thread, or the last thread, exits the process.

                VALUErb_thread_kill(VALUE thread){    rb_thread_t *th = rb_thread_ptr(thread);    if (th->to_kill || th->status == THREAD_KILLED) {        return thread;    }    if (th == th->vm->ractor.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;}
fetch(sym) → objclick to toggle source
fetch(sym) { } → obj
fetch(sym, default) → obj

Returns a fiber-local for the given key. If the key can't be found,there are several options: With no other arguments, it will raise aKeyError exception; ifdefault is given,then that will be returned; if the optional code block is specified, thenthat will be run and its result returned. See#[] andHash#fetch.

                static VALUErb_thread_fetch(int argc, VALUE *argv, VALUE self){    VALUE key, val;    ID id;    rb_thread_t *target_th = rb_thread_ptr(self);    int block_given;    rb_check_arity(argc, 1, 2);    key = argv[0];    block_given = rb_block_given_p();    if (block_given && argc == 2) {        rb_warn("block supersedes default value argument");    }    id = rb_check_id(&key);    if (id == recursive_key) {        return target_th->ec->local_storage_recursive_hash;    }    else if (id && target_th->ec->local_storage &&             rb_id_table_lookup(target_th->ec->local_storage, id, &val)) {        return val;    }    else if (block_given) {        return rb_yield(key);    }    else if (argc == 1) {        rb_key_err_raise(rb_sprintf("key not found: %+"PRIsVALUE, key), self, key);    }    else {        return argv[1];    }}
group → thgrp or nilclick to toggle source

Returns theThreadGroup which contains thegiven thread, or returnsnil ifthr is not amember of any group.

Thread.main.group#=> #<ThreadGroup:0x4029d914>
                VALUErb_thread_group(VALUE thread){    VALUE group = rb_thread_ptr(thread)->thgroup;    return group == 0 ? Qnil : group;}
inspect()click to toggle source
Alias for:to_s
join → thrclick to toggle source
join(limit) → thr

The calling thread will suspend execution and run thisthr.

Does not return untilthr exits or until the givenlimit seconds have passed.

If the time limit expires,nil will be returned, otherwisethr is returned.

Any threads not joined will be killed when the main program exits.

Ifthr had previously raised an exception and the::abort_on_exception or$DEBUG flags are not set, (so the exception has not yet been processed), itwill 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 thread x finish, thread a will be killed on exit.#=> "axyz"

The following example illustrates thelimit parameter.

y =Thread.new {4.times {sleep0.1;puts'tick... ' }}puts"Waiting"untily.join(0.15)

This will produce:

tick...Waitingtick...Waitingtick...tick...
                static VALUEthread_join_m(int argc, VALUE *argv, VALUE self){    VALUE timeout = Qnil;    if (rb_check_arity(argc, 0, 1)) {        timeout = argv[0];    }    // Convert the timeout eagerly, so it's always converted and deterministic    if (timeout == Qnil) {        /* unlimited */    }    else if (FIXNUM_P(timeout)) {        /* handled directly in thread_join_sleep() */    }    else {        timeout = rb_to_float(timeout);    }    return thread_join(rb_thread_ptr(self), timeout);}
key?(sym) → true or falseclick to toggle source

Returnstrue if the given string (or symbol) exists as afiber-local variable.

me =Thread.currentme[:oliver] ="a"me.key?(:oliver)#=> trueme.key?(:stanley)#=> false
                static VALUErb_thread_key_p(VALUE self, VALUE key){    VALUE val;    ID id = rb_check_id(&key);    struct rb_id_table *local_storage = rb_thread_ptr(self)->ec->local_storage;    if (!id || local_storage == NULL) {        return Qfalse;    }    else if (rb_id_table_lookup(local_storage, id, &val)) {        return Qtrue;    }    else {        return Qfalse;    }}
keys → arrayclick to toggle source

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

thr =Thread.newdoThread.current[:cat] ='meow'Thread.current["dog"] ='woof'endthr.join#=> #<Thread:0x401b3f10 dead>thr.keys#=> [:dog, :cat]
                static VALUErb_thread_keys(VALUE self){    struct rb_id_table *local_storage = rb_thread_ptr(self)->ec->local_storage;    VALUE ary = rb_ary_new();    if (local_storage) {        rb_id_table_foreach(local_storage, thread_keys_i, (void *)ary);    }    return ary;}
exit → thrclick to toggle source
kill → thr
terminate → thr

Terminatesthr and schedules another thread to be run,returning the terminatedThread. If this is themain thread, or the last thread, exits the process.

                VALUErb_thread_kill(VALUE thread){    rb_thread_t *th = rb_thread_ptr(thread);    if (th->to_kill || th->status == THREAD_KILLED) {        return thread;    }    if (th == th->vm->ractor.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 → stringclick to toggle source

show the name of the thread.

                static VALUErb_thread_getname(VALUE thread){    return rb_thread_ptr(thread)->name;}
name=(name) → stringclick to toggle source

set given name to the ruby thread. On some platform, it may set the name topthread and/or kernel.

                static VALUErb_thread_setname(VALUE thread, VALUE name){    rb_thread_t *target_th = rb_thread_ptr(thread);    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);    }    target_th->name = name;    if (threadptr_initialized(target_th)) {        native_set_another_thread_name(target_th->thread_id, name);    }    return name;}
pending_interrupt?(error = nil) → true/falseclick to toggle source

Returns whether or not the asynchronous queue is empty for the targetthread.

Iferror is given, then check only forerror typedeferred events.

See::pending_interrupt?for more information.

                static VALUErb_thread_pending_interrupt_p(int argc, VALUE *argv, VALUE target_thread){    rb_thread_t *target_th = rb_thread_ptr(target_thread);    if (!target_th->pending_interrupt_queue) {        return Qfalse;    }    if (rb_threadptr_pending_interrupt_empty_p(target_th)) {        return Qfalse;    }    if (rb_check_arity(argc, 0, 1)) {        VALUE err = argv[0];        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;        }    }    else {        return Qtrue;    }}
priority → integerclick to toggle source

Returns the priority ofthr. Default is inherited from the currentthread 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 someplatform.

Thread.current.priority#=> 0
                static VALUErb_thread_priority(VALUE thread){    return INT2NUM(rb_thread_ptr(thread)->priority);}
priority= integer → thrclick to toggle source

Sets the priority ofthr tointeger. Higher-prioritythreads will run more frequently than lower-priority threads (butlower-priority threads can also run).

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

count1 =count2 =0a =Thread.newdoloop {count1+=1 }enda.priority =-1b =Thread.newdoloop {count2+=1 }endb.priority =-2sleep1#=> 1count1#=> 622504count2#=> 5832
                static VALUErb_thread_priority_set(VALUE thread, VALUE prio){    rb_thread_t *target_th = rb_thread_ptr(thread);    int priority;#if USE_NATIVE_THREAD_PRIORITY    target_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;    }    target_th->priority = (int8_t)priority;#endif    return INT2NUM(target_th->priority);}
raiseclick to toggle source
raise(string)
raise(exception [, string [, array]])

Raises an exception from the given thread. The caller does not have to bethr. SeeKernel#raisefor more information.

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

This will produce:

prog.rb:3: Gotcha (RuntimeError) from prog.rb:2:in `initialize' from prog.rb:2:in `new' from prog.rb:2
                static VALUEthread_raise_m(int argc, VALUE *argv, VALUE self){    rb_thread_t *target_th = rb_thread_ptr(self);    const rb_thread_t *current_th = GET_THREAD();    threadptr_check_pending_interrupt_queue(target_th);    rb_threadptr_raise(target_th, argc, argv);    /* To perform Thread.current.raise as Kernel.raise */    if (current_th == target_th) {        RUBY_VM_CHECK_INTS(target_th->ec);    }    return Qnil;}
report_on_exception → true or falseclick to toggle source

Returns the status of the thread-local “report on exception''condition for thisthr.

The default value when creating aThread is thevalue of the global flag::report_on_exception.

See alsoreport_on_exception=.

There is also a class level method to set this for all new threads, see::report_on_exception=.

                static VALUErb_thread_report_exc(VALUE thread){    return rb_thread_ptr(thread)->report_on_exception ? Qtrue : Qfalse;}
report_on_exception= boolean → true or falseclick to toggle source

When set totrue, a message is printed on $stderr if anexception kills thisthr. See::report_on_exceptionfor details.

See alsoreport_on_exception.

There is also a class level method to set this for all new threads, see::report_on_exception=.

                static VALUErb_thread_report_exc_set(VALUE thread, VALUE val){    rb_thread_ptr(thread)->report_on_exception = RTEST(val);    return val;}
run → thrclick to toggle source

Wakes upthr, making it eligible for scheduling.

a =Thread.new {puts"a";Thread.stop;puts"c" }sleep0.1whilea.status!='sleep'puts"Got here"a.runa.join

This will produce:

aGotherec

See also the instance methodwakeup.

                VALUErb_thread_run(VALUE thread){    rb_thread_wakeup(thread);    rb_thread_schedule();    return thread;}
set_trace_func(proc) → procclick to toggle source
set_trace_func(nil) → nil

Establishesproc onthr as the handler for tracing, ordisables tracing if the parameter isnil.

SeeKernel#set_trace_func.

                static VALUEthread_set_trace_func_m(VALUE target_thread, VALUE trace){    rb_execution_context_t *ec = GET_EC();    rb_thread_t *target_th = rb_thread_ptr(target_thread);    rb_threadptr_remove_event_hook(ec, target_th, call_trace_func, Qundef);    if (NIL_P(trace)) {        return Qnil;    }    else {        thread_add_trace_func(ec, target_th, trace);        return trace;    }}
status → string, false or nilclick to toggle source

Returns the status ofthr.

"sleep"

Returned if this thread is sleeping or waiting on I/O

"run"

When this thread is executing

"aborting"

If this thread is aborting

false

When this thread is terminated normally

nil

If 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#=> nilb.status#=> "sleep"c.status#=> falsed.status#=> "aborting"Thread.current.status#=> "run"

See also the instance methodsalive? andstop?

                static VALUErb_thread_status(VALUE thread){    rb_thread_t *target_th = rb_thread_ptr(thread);    if (rb_threadptr_dead(target_th)) {        if (!NIL_P(target_th->ec->errinfo) &&            !FIXNUM_P(target_th->ec->errinfo)) {            return Qnil;        }        else {            return Qfalse;        }    }    else {        return rb_str_new2(thread_status_name(target_th, FALSE));    }}
stop? → true or falseclick to toggle source

Returnstrue ifthr is dead or sleeping.

a =Thread.new {Thread.stop }b =Thread.currenta.stop?#=> trueb.stop?#=> false

See alsoalive? andstatus.

                static VALUErb_thread_stop_p(VALUE thread){    rb_thread_t *th = rb_thread_ptr(thread);    if (rb_threadptr_dead(th)) {        return Qtrue;    }    else if (th->status == THREAD_STOPPED ||             th->status == THREAD_STOPPED_FOREVER) {        return Qtrue;    }    else {        return Qfalse;    }}
terminate → thrclick to toggle source

Terminatesthr and schedules another thread to be run,returning the terminatedThread. If this is themain thread, or the last thread, exits the process.

                VALUErb_thread_kill(VALUE thread){    rb_thread_t *th = rb_thread_ptr(thread);    if (th->to_kill || th->status == THREAD_KILLED) {        return thread;    }    if (th == th->vm->ractor.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 falseclick to toggle source

Returnstrue if the given string (or symbol) exists as athread-local variable.

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

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

                static VALUErb_thread_variable_p(VALUE thread, VALUE key){    VALUE locals;    if (LIKELY(!THREAD_LOCAL_STORAGE_INITIALISED_P(thread))) {        return Qfalse;    }    locals = rb_thread_local_storage(thread);    if (rb_hash_lookup(locals, rb_to_symbol(key)) != Qnil) {        return Qtrue;    }    else {        return Qfalse;    }    return Qfalse;}
thread_variable_get(key) → obj or nilclick to toggle source

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

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

Thread.new {Thread.current.thread_variable_set("foo","bar")# set a thread localThread.current["foo"] ="bar"# set a fiber localFiber.new {Fiber.yield [Thread.current.thread_variable_get("foo"),# get the thread localThread.current["foo"],# get the fiber local    ]  }.resume}.join.value# => ['bar', nil]

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

                static VALUErb_thread_variable_get(VALUE thread, VALUE key){    VALUE locals;    if (LIKELY(!THREAD_LOCAL_STORAGE_INITIALISED_P(thread))) {        return Qnil;    }    locals = rb_thread_local_storage(thread);    return rb_hash_aref(locals, rb_to_symbol(key));}
thread_variable_set(key, value)click to toggle source

Sets a thread local withkey tovalue. Note thatthese are local to threads, and not to fibers. Please see#thread_variable_getand#[] for more information.

                static VALUErb_thread_variable_set(VALUE thread, VALUE key, VALUE val){    VALUE locals;    if (OBJ_FROZEN(thread)) {        rb_frozen_error_raise(thread, "can't modify frozen thread locals");    }    locals = rb_thread_local_storage(thread);    return rb_hash_aset(locals, rb_to_symbol(key), val);}
thread_variables → arrayclick to toggle source

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

thr =Thread.newdoThread.current.thread_variable_set(:cat,'meow')Thread.current.thread_variable_set("dog",'woof')endthr.join#=> #<Thread:0x401b3f10 dead>thr.thread_variables#=> [:dog, :cat]

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

                static VALUErb_thread_variables(VALUE thread){    VALUE locals;    VALUE ary;    ary = rb_ary_new();    if (LIKELY(!THREAD_LOCAL_STORAGE_INITIALISED_P(thread))) {        return ary;    }    locals = rb_thread_local_storage(thread);    rb_hash_foreach(locals, keys_i, ary);    return ary;}
to_s → stringclick to toggle source

Dump the name, id, and status ofthr to a string.

                static VALUErb_thread_to_s(VALUE thread){    VALUE cname = rb_class_path(rb_obj_class(thread));    rb_thread_t *target_th = rb_thread_ptr(thread);    const char *status;    VALUE str, loc;    status = thread_status_name(target_th, TRUE);    str = rb_sprintf("#<%"PRIsVALUE":%p", cname, (void *)thread);    if (!NIL_P(target_th->name)) {        rb_str_catf(str, "@%"PRIsVALUE, target_th->name);    }    if ((loc = threadptr_invoke_proc_location(target_th)) != Qnil) {        rb_str_catf(str, " %"PRIsVALUE":%"PRIsVALUE,                    RARRAY_AREF(loc, 0), RARRAY_AREF(loc, 1));        rb_gc_force_recycle(loc);    }    rb_str_catf(str, " %s>", status);    return str;}
Also aliased as:inspect
value → objclick to toggle source

Waits forthr to complete, usingjoin, and returns its value or raisesthe exception which terminated the thread.

a =Thread.new {2+2 }a.value#=> 4b =Thread.new {raise'something went wrong' }b.value#=> RuntimeError: something went wrong
                static VALUEthread_value(VALUE self){    rb_thread_t *th = rb_thread_ptr(self);    thread_join(th, Qnil);    return th->value;}
wakeup → thrclick to toggle source

Marks a given thread as eligible for scheduling, however it may stillremain blocked on I/O.

Note: This does not invoke the scheduler, seerun for more information.

c =Thread.new {Thread.stop;puts"hey!" }sleep0.1whilec.status!='sleep'c.wakeupc.join#=> "hey!"
                VALUErb_thread_wakeup(VALUE thread){    if (!RTEST(rb_thread_wakeup_alive(thread))) {        rb_raise(rb_eThreadError, "killed thread");    }    return thread;}

This page was generated for Ruby 3.0.0

Generated with Ruby-doc Rdoc Generator 0.42.0.


[8]ページ先頭

©2009-2025 Movatter.jp