U:RDoc::NormalClass[iI" Thread:ET@I" Object;To:RDoc::Markup::Document: @parts[o;;[: @fileI"prelude.rb;T:0@omit_headings_from_table_of_contents_below0o;;[; I"thread_sync.c;T; 0o;;[So:RDoc::Markup::Paragraph;[I"LThreads are the Ruby implementation for a concurrent programming model.;To:RDoc::Markup::BlankLineo; ;[I"GPrograms that require multiple threads of execution are a perfect ;TI"'candidate for Ruby's Thread class.;T@o; ;[I"MFor example, we can create a new thread separate from the main thread's ;TI"execution using ::new.;T@o:RDoc::Markup::Verbatim;[I"4thr = Thread.new { puts "Whats the big deal" } ;T: @format0o; ;[I"JThen we are able to pause the execution of the main thread and allow ;TI"+our new thread to finish, using #join:;T@o; ;[I"'thr.join #=> "Whats the big deal" ;T;0o; ;[I"MIf we don't call +thr.join+ before the main thread terminates, then all ;TI"2other threads including +thr+ will be killed.;T@o; ;[I"JAlternatively, you can use an array for handling multiple threads at ;TI")once, like in the following example:;T@o; ;[I"threads = [] ;TI"9threads << Thread.new { puts "Whats the big deal" } ;TI"Cthreads << Thread.new { 3.times { puts "Threads are fun!" } } ;T;0o; ;[I"AAfter creating a few threads we wait for them all to finish ;TI"consecutively.;T@o; ;[I"%threads.each { |thr| thr.join } ;T;0S:RDoc::Markup::Heading: leveli: textI"Thread initialization;T@o; ;[I"GIn order to create new threads, Ruby provides ::new, ::start, and ;TI"L::fork. A block must be provided with each of these methods, otherwise ;TI""a ThreadError will be raised.;T@o; ;[I"HWhen subclassing the Thread class, the +initialize+ method of your ;TI"Ksubclass will be ignored by ::start and ::fork. Otherwise, be sure to ;TI",call super in your +initialize+ method.;T@S;;i;I"Thread termination;T@o; ;[I"IFor terminating threads, Ruby provides a variety of ways to do this.;T@o; ;[I">The class method ::kill, is meant to exit a given thread:;T@o; ;[I"thr = Thread.new { ... } ;TI",Thread.kill(thr) # sends exit() to thr ;T;0o; ;[I"IAlternatively, you can use the instance method #exit, or any of its ;TI"!aliases #kill or #terminate.;T@o; ;[I"thr.exit ;T;0S;;i;I"Thread status;T@o; ;[I"LRuby provides a few instance methods for querying the state of a given ;TI"Hthread. To get a string with the current thread's state use #status;T@o; ;[ I" thr = Thread.new { sleep } ;TI"thr.status # => "sleep" ;TI"thr.exit ;TI"thr.status # => false ;T;0o; ;[I"LYou can also use #alive? to tell if the thread is running or sleeping, ;TI"2and #stop? if the thread is dead or sleeping.;T@S;;i;I"Thread variables and scope;T@o; ;[I"JSince threads are created with blocks, the same rules apply to other ;TI"MRuby blocks for variable scope. Any local variables created within this ;TI".block are accessible to only this thread.;T@S;;i ;I"!Fiber-local vs. Thread-local;T@o; ;[I"IEach fiber has its own bucket for Thread#[] storage. When you set a ;TI"Lnew fiber-local it is only accessible within this Fiber. To illustrate:;T@o; ;[ I"Thread.new { ;TI"$ Thread.current[:foo] = "bar" ;TI" Fiber.new { ;TI") p Thread.current[:foo] # => nil ;TI" }.resume ;TI" }.join ;T;0o; ;[I"JThis example uses #[] for getting and #[]= for setting fiber-locals, ;TI"Ayou can also use #keys to list the fiber-locals for a given ;TI"7thread and #key? to check if a fiber-local exists.;T@o; ;[I"KWhen it comes to thread-locals, they are accessible within the entire ;TI"6scope of the thread. Given the following example:;T@o; ;[I"Thread.new{ ;TI"3 Thread.current.thread_variable_set(:foo, 1) ;TI"9 p Thread.current.thread_variable_get(:foo) # => 1 ;TI" Fiber.new{ ;TI"5 Thread.current.thread_variable_set(:foo, 2) ;TI"; p Thread.current.thread_variable_get(:foo) # => 2 ;TI" }.resume ;TI"; p Thread.current.thread_variable_get(:foo) # => 2 ;TI" }.join ;T;0o; ;[I"JYou can see that the thread-local +:foo+ carried over into the fiber ;TI"5and was changed to +2+ by the end of the thread.;T@o; ;[I"BThis example makes use of #thread_variable_set to create new ;TI"?thread-locals, and #thread_variable_get to reference them.;T@o; ;[I"DThere is also #thread_variables to list all thread-locals, and ;TI"?#thread_variable? to check if a given thread-local exists.;T@S;;i;I"Exception handling;T@o; ;[I"IAny thread can raise an exception using the #raise instance method, ;TI".which operates similarly to Kernel#raise.;T@o; ;[ I"JHowever, it's important to note that an exception that occurs in any ;TI"Hthread except the main thread depends on #abort_on_exception. This ;TI"Moption is +false+ by default, meaning that any unhandled exception will ;TI"Kcause the thread to terminate silently when waited on by either #join ;TI"Kor #value. You can change this default by either #abort_on_exception= ;TI"(+true+ or setting $DEBUG to +true+.;T@o; ;[I"KWith the addition of the class method ::handle_interrupt, you can now ;TI"3handle exceptions asynchronously with threads.;T@S;;i;I"Scheduling;T@o; ;[I"LRuby provides a few ways to support scheduling threads in your program.;T@o; ;[I"KThe first way is by using the class method ::stop, to put the current ;TI"Jrunning thread to sleep and schedule the execution of another thread.;T@o; ;[I"IOnce a thread is asleep, you can use the instance method #wakeup to ;TI"1mark your thread as eligible for scheduling.;T@o; ;[ I"JYou can also try ::pass, which attempts to pass execution to another ;TI"Lthread but is dependent on the OS whether a running thread will switch ;TI"Lor not. The same goes for #priority, which lets you hint to the thread ;TI"Fscheduler which threads you want to take precedence when passing ;TI"Kexecution. This method is also dependent on the OS and may be ignored ;TI"on some platforms.;T; I" vm.c;T; 0; 0; 0[[[[[I" class;T[[: public[[I" DEBUG;TI" thread.c;T[I" DEBUG=;T@Ï[I"abort_on_exception;T@Ï[I"abort_on_exception=;T@Ï[I" current;T@Ï[I"exclusive;FI"prelude.rb;T[I" exit;T@Ï[I" fork;T@Ï[I"handle_interrupt;T@Ï[I" kill;T@Ï[I" list;T@Ï[I" main;T@Ï[I"new;T@Ï[I" pass;T@Ï[I"pending_interrupt?;T@Ï[I"report_on_exception;T@Ï[I"report_on_exception=;T@Ï[I" start;T@Ï[I" stop;T@Ï[:protected[[: private[[I" instance;T[[;[([I"[];T@Ï[I"[]=;T@Ï[I"abort_on_exception;T@Ï[I"abort_on_exception=;T@Ï[I"add_trace_func;TI"vm_trace.c;T[I" alive?;T@Ï[I"backtrace;T@Ï[I"backtrace_locations;T@Ï[I" exit;T@Ï[I" group;T@Ï[I" inspect;T@Ï[I" join;T@Ï[I" key?;T@Ï[I" keys;T@Ï[I" kill;T@Ï[I" name;T@Ï[I" name=;T@Ï[I"pending_interrupt?;T@Ï[I" priority;T@Ï[I"priority=;T@Ï[I" raise;T@Ï[I"report_on_exception;T@Ï[I"report_on_exception=;T@Ï[I"run;T@Ï[I"safe_level;T@Ï[I"set_trace_func;T@[I" status;T@Ï[I" stop?;T@Ï[I"terminate;T@Ï[I"thread_variable?;T@Ï[I"thread_variable_get;T@Ï[I"thread_variable_set;T@Ï[I"thread_variables;T@Ï[I" value;T@Ï[I" wakeup;T@Ï[;[[;[[[U:RDoc::Context::Section[i0o;;[; 0; 0[ @ I" thread.c;T@@ÃI"vm_trace.c;T@QcRDoc::TopLevel