Skip to content

Instantly share code, notes, and snippets.

@ahoward
Created June 25, 2009 04:49
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save ahoward/135689 to your computer and use it in GitHub Desktop.
Save ahoward/135689 to your computer and use it in GitHub Desktop.
require 'thread'
require 'timeout'
class ObjectPool
attr_reader :max
attr_accessor :timeout
attr_accessor :create
attr_accessor :objects
attr_accessor :used
def initialize(*args, &block)
@max = Integer(args.shift || 10)
@timeout = nil
@objects = []
@used = {}
@mutex = Mutex.new
@cond = ConditionVariable.new
@create = block
end
def get(&block)
object = nil
@mutex.synchronize {
if !@objects.empty?
object = @objects.pop
elsif @used.size < @max
object = create ? create.call : nil
else
Timeout.timeout(@timeout){ @cond.wait(@mutex) }
object = @objects.pop
end
@used.store(object.__id__, object)
}
if block
begin
block.call(object)
ensure
release(object)
end
else
object
end
end
def release(object)
@mutex.synchronize {
@used.delete(object.__id__)
@objects.push(object)
@cond.signal
}
object
end
def max=(size)
@mutex.synchronize {
if @objects.size + @used.size > size
raise ArgumentError.new("Cannot change max size to %d. There are objects over the size." % size)
end
@max = size
}
size
end
end
if $0 == __FILE__
pool = ObjectPool.new{ Array.new }
n = 2**16
Thread.new do
Thread.current.abort_on_exception=true
n.times{ 10.times{ pool.get{} } }
end
n.times do
Thread.new do
Thread.current.abort_on_exception=true
sleep rand
Thread.new do
Thread.current.abort_on_exception=true
sleep rand
pool.get do |array|
array.push Thread.current.object_id
end
end
end
end
Thread.list.map{|t| t.join unless Thread.current==t}
values = pool.objects.flatten
p values.size
p values.uniq.size
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment