lib/knj/threadhandler.rb in knjrbfw-0.0.8 vs lib/knj/threadhandler.rb in knjrbfw-0.0.9

- old
+ new

@@ -1,41 +1,48 @@ class Knj::Threadhandler - attr_reader :inactive_blocks, :args, :activate_blocks, :mutex - - def initialize(args = {}) - @args = args - @objects = [] - @args[:timeout] = 5 if !@args[:timeout] - @inactive_blocks = [] - @activate_blocks = [] - @mutex = Mutex.new - - @thread_timeout = Knj::Thread.new do - loop do - sleep @args[:timeout] - break if !@mutex - check_inactive - end - end - end - - def on_spawn_new(&block) + attr_reader :inactive_blocks, :args, :activate_blocks, :mutex, :objects + + def initialize(args = {}) + require "#{$knjpath}errors" + + @args = args + @objects = [] + @args[:timeout] = 5 if !@args[:timeout] + @args[:max] = 50 if !@args[:max] + @inactive_blocks = [] + @activate_blocks = [] + @mutex = Mutex.new + + @thread_timeout = Thread.new do + begin + loop do + sleep @args[:timeout] + break if !@mutex + check_inactive + end + rescue => e + STDOUT.print Knj::Errors.error_str(e) + end + end + end + + def on_spawn_new(&block) raise "Destroyed Knj::Threadhandler." if !@mutex - @spawn_new_block = block - end - - def on_inactive(&block) + @spawn_new_block = block + end + + def on_inactive(&block) raise "Destroyed Knj::Threadhandler." if !@mutex - @inactive_blocks << block - end - - def on_activate(&block) + @inactive_blocks << block + end + + def on_activate(&block) raise "Destroyed Knj::Threadhandler." if !@mutex - @activate_blocks << block - end - - def destroy + @activate_blocks << block + end + + def destroy return false if !@mutex @thread_timeout.kill if @thread_timeout and @thread_timeout.alive? @thread_timeout = nil @@ -51,80 +58,106 @@ @args = nil @objects = nil @inactive_blocks = nil @activate_blocks = nil @mutex = nil - end - - def check_inactive + end + + def check_inactive raise "Destroyed Knj::Threadhandler." if !@mutex - @mutex.synchronize do - cur_time = Time.new.to_i - @args[:timeout] - @objects.each do |data| - if data[:free] and !data[:inactive] and data[:free] < cur_time - @inactive_blocks.each do |block| - data[:inactive] = true - block.call(:obj => data[:object]) - end - end - end - end - end - - def get_and_lock + @mutex.synchronize do + cur_time = Time.now.to_i - @args[:timeout] + @objects.each do |data| + if data[:free] and !data[:inactive] and data[:free] < cur_time + @inactive_blocks.each do |block| + data[:inactive] = true + block.call(:obj => data[:object]) + end + end + end + end + end + + def get_and_lock raise "Destroyed Knj::Threadhandler." if !@mutex - newobj = nil - - @mutex.synchronize do - retdata = false - @objects.each do |data| - if data[:free] - retdata = data - break - end - end - - if retdata - #Test if object is still free - if not, try again - knj. - return get_and_lock if !retdata[:free] - retdata[:free] = false - - if retdata[:inactive] - @activate_blocks.each do |block| - block.call(:obj => retdata[:object]) - end - - retdata.delete(:inactive) - end - - return retdata[:object] - end - - newobj = @spawn_new_block.call - @objects << { - :free => false, - :object => newobj - } - STDOUT.print "Spawned db and locked new.\n" if @args[:debug] - end - - return newobj - end - - def free(obj) - @mutex.synchronize do + newobj = nil + sleep_do = false + + begin + @mutex.synchronize do + retdata = false + @objects.each do |data| + if data[:free] + retdata = data + break + end + end + + if retdata + #Test if object is still free - if not, try again - knj. + return get_and_lock if !retdata[:free] + retdata[:free] = false + + if retdata[:inactive] + @activate_blocks.each do |block| + block.call(:obj => retdata[:object]) + end + + retdata.delete(:inactive) + end + + return retdata[:object] + end + + if @objects.length >= @args[:max] + #The maximum amount of objects has already been spawned... Sleep 0.1 sec and try to lock an object again... + raise Knj::Errors::Retry + else + #No free objects, but we can spawn a new one and use that... + newobj = @spawn_new_block.call + @objects << { + :free => false, + :object => newobj + } + STDOUT.print "Spawned db and locked new.\n" if @args[:debug] + end + end + + return newobj + rescue Knj::Errors::Retry + STDOUT.print "All objects was taken - sleeping 0.1 sec and tries again.\n" #if @args[:debug] + sleep 0.1 + retry + end + end + + def free(obj) + @mutex.synchronize do return false if !@mutex or !@objects #something is trying to free and object, but the handler is destroyed. Dont crash but return false. - freedata = false - @objects.each do |data| - if data[:object] == obj - freedata = data - break - end - end - - raise "Could not find that object in list." if !freedata - STDOUT.print "Freed one.\n" if @args[:debug] - freedata[:free] = Time.new.to_i - end - end + freedata = false + @objects.each do |data| + if data[:object] == obj + freedata = data + break + end + end + + raise "Could not find that object in list." if !freedata + STDOUT.print "Freed one.\n" if @args[:debug] + freedata[:free] = Time.now.to_i + end + end + + #Executes the given block with an element and then frees it. + def use + raise "No block was given." if !block_given? + + obj = self.get_and_lock + + begin + yield(obj) + ensure + self.free(obj) + end + end end \ No newline at end of file