> I'd like to detect "no work left" as a case of the "farmer" going out of
> scope, if possible.
In principle, if the Farmer is an object, then it can have a finalizer
which sends the terminate message to all the workers. The finalizer
won't be called immediately when the Farmer goes out of scope, but at
some time later.
In practice, it isn't easy to do. The finalizer is only called *after*
the farmer has been destroyed, so you can't use any methods or instance
variables on it. And I find it very hard to demonstrate in practice. The
following attempt is broken and I can't see what's wrong:
#---- 8< --------------
require 'thread'
class Farmer
attr_reader :queue, :workers
def self.cleanup(workers)
lambda { |id|
workers.each { |t| p t; Thread.kill(t) }
}
end
def self.create
farmer = new
workers = farmer.workers
ObjectSpace.define_finalizer(farmer, cleanup(workers))
farmer
end
def self.make_worker(queue)
Thread.new do
loop do
puts queue.pop
end
end
end
def initialize
@workers = []
@queue = Queue.new
end
def add_worker
@workers << self.class.make_worker(queue)
end
def push(x)
@queue.push(x)
end
end
def testit
f = Farmer.create
3.times { f.add_worker }
f.push("hello")
f.push("world")
end
10.times { testit }
GC.start
# For some reason the farmers still exist
ObjectSpace.each_object(Farmer) { |f| p f }
puts "End of the world"
sleep 1
#---- 8< --------------
When I run this, I see that the finalizers are indeed called when ruby
terminates - but not when garbage-collection is requested. Indeed, the
Farmers remain in ObjectSpace even after garbage collection. I can't see
why that should be.
I've tried to ensure that neither the finalizer lambda nor the worker
threads have the farmer bound to their environment, and I can't see what
else is holding a reference. This is with ruby 1.8.6 (2008-03-03
patchlevel 114) [i686-linux]
Regards,
Brian.
--
Posted via http://www.ruby-forum.com/.