From 2c1706fffb3fed17085af23de26ce84ed8ebae1a Mon Sep 17 00:00:00 2001 From: ocean Date: Fri, 30 Dec 2005 09:29:07 +0000 Subject: [PATCH] * lib/generator.rb: uses Mutex instead of Thread.critical. [ruby-dev:28184] git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@9773 b2dd03c8-39d4-4d8f-98ff-823fe69b080e --- ChangeLog | 5 ++++ lib/generator.rb | 61 ++++++++++++++++++++++++------------------------ 2 files changed, 36 insertions(+), 30 deletions(-) diff --git a/ChangeLog b/ChangeLog index 9f03661c77..cbd37bb6e6 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,8 @@ +Fri Dec 30 18:27:00 2005 Hirokazu Yamamoto + + * lib/generator.rb: uses Mutex instead of Thread.critical. + [ruby-dev:28184] + Fri Dec 30 18:22:42 2005 Nobuyoshi Nakada * gc.c (garbage_collect): mark objects refered from aborting threads. diff --git a/lib/generator.rb b/lib/generator.rb index 241987faba..19f2385449 100644 --- a/lib/generator.rb +++ b/lib/generator.rb @@ -23,6 +23,7 @@ # # See the respective classes for examples of usage. +require "thread" # # Generator converts an internal iterator (i.e. an Enumerable object) @@ -71,17 +72,24 @@ class Generator end @index = 0 @queue = [] + @mutex = Mutex.new + @main_cond = ConditionVariable.new + @loop_cond = ConditionVariable.new + entered = false @loop_thread = Thread.new do - Thread.stop - begin - @block.call(self) - rescue - @main_thread.raise - ensure - @main_thread.wakeup + @mutex.synchronize do + entered = true + @loop_cond.wait(@mutex) + begin + @block.call(self) + rescue + @main_thread.raise $! + ensure + @main_cond.signal + end end end - Thread.pass until @loop_thread.stop? + Thread.pass until entered && !@mutex.locked? self end @@ -90,33 +98,26 @@ class Generator if Thread.current != @loop_thread raise "should be called in Generator.new{|g| ... }" end - Thread.critical = true - begin - @queue << value - @main_thread.wakeup - Thread.stop - ensure - Thread.critical = false - end + @queue << value + @main_cond.signal + @loop_cond.wait(@mutex) self end # Returns true if the generator has reached the end. def end? - if @queue.empty? - if @main_thread - raise "should not be called in Generator.new{|g| ... }" - end - Thread.critical = true - begin - @main_thread = Thread.current - @loop_thread.wakeup - Thread.stop - rescue ThreadError - # ignore - ensure - @main_thread = nil - Thread.critical = false + @mutex.synchronize do + if @queue.empty? && @loop_thread.alive? + if @main_thread + raise "should not be called in Generator.new{|g| ... }" + end + begin + @main_thread = Thread.current + @loop_cond.signal + @main_cond.wait(@mutex) + ensure + @main_thread = nil + end end end @queue.empty?