Threads spawning more threads

Stylish 0 Tallied Votes 124 Views Share

I needed a way to spawn multiple threads, have them monitored, and restarted if an error occured. I came up with the following.

This snippet is from a larger program, so if there is a problem please let me know. This is for command line and tested on Linux (well, the larger program).

<% #!/usr/bin/env ruby ## kill some warnings about writable directories $VERBOSE=nil # we want to parse input, right? require 'optparse' ## global options (which can and will be changed) @@options = { :runtime => "01:00:00", :total_time => 0, :threadlist => [], } def parse_input() ARGV.options do |opts| opts.banner = "Usage: #{$0} [options] <thread names>" opts.separator "Threadeds spawning threads, oh my!" opts.separator "" opts.separator "Options:" opts.on("-h", "--help", "show this message") { puts opts exit } opts.on("-v", "--version", "show version details") { version = `grep -m 1 "#(@)" #{$0} | awk '{printf("version: %s (%s)",$3,$2)}'` puts version exit } opts.on("--duration=HH:MM:SS", String, "specify how long to run test (default: #{@@options[:runtime]})") { |@@options[:runtime]| } opts.parse! end ## validate time hours, mins, secs = @@options[:runtime].to_s.split(":") if hours.nil? or mins.nil? or secs.nil? puts "ERROR -- Invalid time format!" exit 1 end @@options[:total_time] = (hours.to_i * 60 * 60) + (mins.to_i * 60) + secs.to_i ## thread list, anyone? if ARGV.length < 1 puts "ERROR! No thread names specified!" exit 1 else @@options[:threadlist] = ARGV end end @threads = [] @start_time = Time.now ## trap ctrl-c trap("INT") { threadDestroyAll() } def newPass(threadname) ## create a new thread and add it to @threads @threads << Thread.new(threadname) { |myThread| ## trap that CTRL-C trap("INT") { threadDestroyAll() } ## name thread to that of name given. easier management Thread.current[:name] = "#{myThread}" ## Stuff for thread to do goes here. } end ## this is triggered via CTRL-C trap above # kill all threads and exit def threadDestroyAll() puts "***************************" puts "** Killing all processes **" puts "***************************" @threads.each { |thread| thread.kill } sleep 2 Thread.main.kill end ## needed a way to watch over all the baby threads # this will cycle through all threads, gathering a list of #+ those that are still running (and their names, which are that of the client) #+ any missing clients are then restarted. def threadOverlord(threads) threadList = activeThreads = deadThreads = [] threadList = @@options[:threadlist] threads.each { |thread| activeThreads << thread[:name] if thread.alive? and keepGoing() } ## restart baby threads that have died? # if time limit has been reached, that is a no if keepGoing() deadThreads = threadList - activeThreads deadThreads.each { |threadname| newPass(threadname) } end activeThreads = deadThreads = threadList = nil end ## parent thread # this is just to trigger threadOverlord every X seconds #+ and check on the health of client threads def statusThread() statusT = Thread.new { Thread.current[:name] = "Overlord" loop do threadOverlord(@threads) sleep 15 break if !keepGoing() end } statusT.join end ## returns true if there is still time remaining def keepGoing() return true if Time.now.to_i - @start_time.to_i < @@options[:total_time].to_i false end parse_input() statusThread %>
close