So here is a class I wrote in ruby.
class LimitedThreads
def initialize max
@group = ThreadGroup.new
@maxthreads = max
@lock = Mutex.new
@slot = ConditionVariable.new
end
def to_s
"max threads: %s; current threads: %s;" % [@maxthreads, @group.list.size]
end
def newthread *args
if @maxthreads <= @group.list.size
#delay until a thread ends
@lock.synchronize { @slot.wait(@lock) }
end
nt = Thread.new do
yield *args #this allows operation like Thread.new for passing in args to thread
@lock.synchronize { @slot.signal }
end
@group.add nt
nt
end
end
You create an object from this with the maximum amount of threads you want it to allow to run at any given time. You use
LimitedThreads#newthread with a block representing the thread you want to run. If the instance has a spot free for that thread, it will run it. Otherwise, it will wait until a already running thread finishes to start up the new thread. Now, this code probably has no real use, but it was an interesting exercise for me. Ruby is interesting in that it uses blocks for threads, not methods. The comment inside the
Thread.new call is on the subject of passing arguments into the block that
LimitedThreads#newthread takes. Anyway, here is an example of how to use it.
lt=LimitedThreads.new 3
sleep_time = 2
12.times do |count|
message = "hello from pass number %s" % count
lt.newthread(message, sleep_time) do |msg, st|
sleep st
puts msg
end
end
On my system, this consistently prints:
hello from pass number 1
hello from pass number 0
hello from pass number 2
hello from pass number 4
hello from pass number 3
hello from pass number 5
hello from pass number 7
hello from pass number 6
hello from pass number 8
Printing each group of three at 2 second interval bursts (all in group appear). Try it on other systems; it might do something else. If you can find a use for it, please, tell me.