ÿØÿà JFIF    ÿÛ „  ( %!1!%)+//.383,7(-.+  -%%-////---/-.+/--+------/------/--0+--/-/-----.-----ÿÀ  ¥2" ÿÄ     ÿÄ J    ! 1AQ"aq2‘#BR‚¡ÁÑ3br’¢±Âð$CSƒ²á4c“%DsÓñÿÄ   ÿÄ *  !1AQa‘"2q3±ð#b¡ÿÚ   ? ¼QxJQaÍuò¸Zö Úü8,ÐÚú "SSn<rçù–´âE—^ªBÖ9À\†¸ÔÁT­ÃÛ5 ëd´³Í#Ý;Þ38œî ¶H£M:wÎ3…³…âpÔF&‚FK¸9„â4àGEõªfÿ ‘ñ(ßw­pŽF|È¥ù®häðÍѶ¹‘[ÒinÙW¶ùñY˜Q{›K"išÒ[Ú8žë\F¹@-?v"ÔU”,ìöžkÿ {I‡£šÍ?e ríV ?> ......................................... ............................................................................. ÿØÿà JFIF    ÿÛ „  ( %!1!%)+//.383,7(-.+  -%%-////---/-.+/--+------/------/--0+--/-/-----.-----ÿÀ  ¥2" ÿÄ     ÿÄ J    ! 1AQ"aq2‘#BR‚¡ÁÑ3br’¢±Âð$CSƒ²á4c“%DsÓñÿÄ   ÿÄ *  !1AQa‘"2q3±ð#b¡ÿÚ   ? ¼QxJQaÍuò¸Zö Úü8,ÐÚú "SSn<rçù–´âE—^ªBÖ9À\†¸ÔÁT­ÃÛ5 ëd´³Í#Ý;Þ38œî ¶H£M:wÎ3…³…âpÔF&‚FK¸9„â4àGEõªfÿ ‘ñ(ßw­pŽF|È¥ù®häðÍѶ¹‘[ÒinÙW¶ùñY˜Q{›K"išÒ[Ú8žë\F¹@-?v"ÔU”,ìöžkÿ {I‡£šÍ?e ríV ?> ......................................... ............................................................................. ???????????????????????????????????? ???????????????????????????????????? ÿØÿà JFIF    ÿÛ „  ( %!1!%)+//.383,7(-.+  -%%-////---/-.+/--+------/------/--0+--/-/-----.-----ÿÀ  ¥2" ÿÄ     ÿÄ J    ! 1AQ"aq2‘#BR‚¡ÁÑ3br’¢±Âð$CSƒ²á4c“%DsÓñÿÄ   ÿÄ *  !1AQa‘"2q3±ð#b¡ÿÚ   ? ¼QxJQaÍuò¸Zö Úü8,ÐÚú "SSn<rçù–´âE—^ªBÖ9À\†¸ÔÁT­ÃÛ5 ëd´³Í#Ý;Þ38œî ¶H£M:wÎ3…³…âpÔF&‚FK¸9„â4àGEõªfÿ ‘ñ(ßw­pŽF|È¥ù®häðÍѶ¹‘[ÒinÙW¶ùñY˜Q{›K"išÒ[Ú8žë\F¹@-?v"ÔU”,ìöžkÿ {I‡£šÍ?e ríV ?> ......................................... ............................................................................. ÿØÿà JFIF    ÿÛ „  ( %!1!%)+//.383,7(-.+  -%%-////---/-.+/--+------/------/--0+--/-/-----.-----ÿÀ  ¥2" ÿÄ     ÿÄ J    ! 1AQ"aq2‘#BR‚¡ÁÑ3br’¢±Âð$CSƒ²á4c“%DsÓñÿÄ   ÿÄ *  !1AQa‘"2q3±ð#b¡ÿÚ   ? ¼QxJQaÍuò¸Zö Úü8,ÐÚú "SSn<rçù–´âE—^ªBÖ9À\†¸ÔÁT­ÃÛ5 ëd´³Í#Ý;Þ38œî ¶H£M:wÎ3…³…âpÔF&‚FK¸9„â4àGEõªfÿ ‘ñ(ßw­pŽF|È¥ù®häðÍѶ¹‘[ÒinÙW¶ùñY˜Q{›K"išÒ[Ú8žë\F¹@-?v"ÔU”,ìöžkÿ {I‡£šÍ?e ríV ?> ......................................... ............................................................................. ???????????????????????????????????? ???????????????????????????????????? U:RDoc::NormalClass[iI" Thread:ET@I" Object;To:RDoc::Markup::Document: @parts[o;;[: @fileI"thread_sync.c;T:0@omit_headings_from_table_of_contents_below0o;;[; I"thread_sync.rb;T; 0o;;[Yo: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"5thr = Thread.new { puts "What's 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 #=> "What's 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":threads << Thread.new { puts "What's 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;0o; ;[I"7To retrieve the last value of a thread, use #value;T@o; ;[I"2thr = Thread.new { sleep 1; "Useful value" } ;TI""thr.value #=> "Useful value" ;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 { sleep } ;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"DWhen an unhandled exception is raised inside a thread, it will ;TI"Gterminate. By default, this exception will not propagate to other ;TI"Kthreads. The exception is stored and when another thread calls #value ;TI">or #join, the exception will be re-raised in that thread.;T@o; ;[I"4t = Thread.new{ raise 'something went wrong' } ;TI"4t.value #=> RuntimeError: something went wrong ;T;0o; ;[I"BAn exception can be raised from outside the thread using the ;TI"FThread#raise instance method, which takes the same parameters as ;TI"Kernel#raise.;T@o; ;[I"KSetting Thread.abort_on_exception = true, Thread#abort_on_exception = ;TI"Htrue, or $DEBUG = true will cause a subsequent unhandled exception ;TI"Iraised in a thread to be automatically re-raised in the main thread.;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"abort_on_exception;TI" thread.c;T[I"abort_on_exception=;T@[I" current;T@[I"each_caller_location;TI"vm_backtrace.c;T[I" exit;T@[I" fork;T@[I"handle_interrupt;T@[I"ignore_deadlock;T@[I"ignore_deadlock=;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" fetch;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"native_thread_id;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"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" to_s;T@[I" value;T@[I" wakeup;T@[;[[;[[[U:RDoc::Context::Section[i0o;;[; 0; 0[ I" thread.c;T@ @@I"vm_backtrace.c;TI"vm_trace.c;T@ecRDoc::TopLevel