From: nobu.nokada@... Date: 2004-01-16T12:20:59+09:00 Subject: Re: Nested scopes and the Singleton pattern Hi, At Fri, 16 Jan 2004 07:46:39 +0900, Christoph wrote: > > > > Just using Thread.critical. And seems close to your idea > > > > excepting for it uses "instance" method rather than "new". > > > > Not accurate, it uses 3-state; before, during and after > > creation, but I feel it should use mutex or something. > > You probably always need a 3-state if you want a self > modifying first instance call (at least in some implicit way). > > Here is a mutexy version of singleton.rb I wrote some time > ago - it is probably more robust then the current code but equally > obscure - sorry ... Due to the line ending codes, your patch contains whole files. Following is a bit modified version. Index: lib/singleton.rb =================================================================== RCS file: /cvs/ruby/src/ruby/lib/singleton.rb,v retrieving revision 1.21 diff -u -2 -p -d -r1.21 singleton.rb --- lib/singleton.rb 22 Aug 2003 08:09:58 -0000 1.21 +++ lib/singleton.rb 16 Jan 2004 01:26:06 -0000 @@ -12,5 +12,5 @@ # a,b = Klass.instance, Klass.instance # a == b # => true -# a.new # NoMethodError - new is private ... +# Klass.new # NoMethodError - new is private ... # # * ``The instance'' is created at instanciation time, in other @@ -31,7 +31,5 @@ # # Providing (or modifying) the class methods -# * Klass.inherited(sub_klass) and Klass.clone() - -# to ensure that the Singleton pattern is properly -# inherited and cloned. +# * Klass.inherited(sub_klass) and Klass.initialize_copy() # # * Klass.instance() - returning ``the instance''. After a @@ -45,20 +43,12 @@ # * Klass._load(str) - calling Klass.instance() # -# * Klass._instanciate?() - returning ``the instance'' or -# nil. This hook method puts a second (or nth) thread calling -# Klass.instance() on a waiting loop. The return value -# signifies the successful completion or premature termination -# of the first, or more generally, current "instanciation thread". -# # # The instance method of Singleton are -# * clone and dup - raising TypeErrors to prevent cloning or duping +# * clone and dup - raising TypeErrors to prevent cloning # -# * _dump(depth) - returning the empty string. Marshalling strips -# by default all state information, e.g. instance variables and -# taint state, from ``the instance''. Providing custom _load(str) -# and _dump(depth) hooks allows the (partially) resurrections of -# a previous state of ``the instance''. - +# * _dump(depth) - returning the empty string, in other words +# marshalling strips all state information. Providing custom +# _load(str) and _dump(depth) hooks allows the (partially) +# resurrections of a previous state of ``the instance''. @@ -82,60 +72,61 @@ end class << Singleton # Method body of first instance call. - FirstInstanceCall = proc do - # @__instance__ takes on one of the following values - # * nil - before and after a failed creation - # * false - during creation - # * sub_class instance - after a successful creation - # the form makes up for the lack of returns in progs - Thread.critical = true - if @__instance__.nil? - @__instance__ = false - Thread.critical = false - begin + FirstInstanceCall = proc do || + critical, Thread.critical = Thread.critical, true + begin + if instanciating = @__instance__.nil? + @__instance__ = false + Thread.critical = critical @__instance__ = new - ensure - if @__instance__ - class < mes + rescue => mes puts mes end } + curr.priority = rand(101) + curr } - puts "Before there were #{num_of_instances(self)}" + puts "Before there existed #{num} valid #{self} instance(s)" sleep 3 - puts "Now there is #{num_of_instances(self)}" - puts "#{@enter.join '; '} was the order of threads entering the waiting loop" - puts "#{@leave.join '; '} was the order of threads leaving the waiting loop" + thrs.each {|t| t.join } + puts "Now there exist(s) #{num} valid #{self} instance(s)" end -end + + def num + cnt = 0 + ObjectSpace.each_object(self) {|o| cnt+=1 if o.valid? } + cnt + end + + private + + def initialize_copy(orig) + super + @attempts = 0 + end +end -Ups.instanciate_all -# results in message like -# Before there were 0 Ups instance(s) -# boom - thread #6 failed to create instance -# initialize called by thread #3 -# Now there is 1 Ups instance(s) -# 3; 2; 1; 8; 4; 7; 5 was the order of threads entering the waiting loop -# 3; 2; 1; 7; 4; 8; 5 was the order of threads leaving the waiting loop +Foo.instanciate_all +# results in something like: +# Before there were 0 valid Foo instance(s) +# boom - initialize failed for thread #78 +# boom - initialize failed for thread #93 +# boom - initialize failed for thread #8 +# yes - initialize succceeded for thread #27 +# Now there are 1 valid Foo instance(s) +# Now there are 1 valid Foo instance(s) puts "\nLets see if class level cloning really works" -Yup = Ups.clone -def Yup.new - begin - __sleep - raise "boom - thread ##{Thread.current[:i]} failed to create instance" - ensure - # simple flip-flop - class << self - remove_method :new - end - end -end -Yup.instanciate_all +Baz = Foo.clone +Baz.instanciate_all -- Nobu Nakada