Joel VanderWerf
2/19/2006
Daniel Sheppard wrote:
> The following probably contains world-destroying race-conditions, but it
> roughly works. Making it work properly is left as an exercise for the
> reader.
>
>
> $stoppable = []
> $stop_all = false
>
> def stop_all
> $stop_all = true
> end
>
> def start_all
> $stop_all = false
> $stoppable.each {|t| p "waking #{t}"; t.wakeup}
> end
>
> set_trace_func proc { |event, file, line, id, binding, classname|
> if $stop_all && $stoppable.include?(Thread.current)
> p "#{Thread.current} stopping"
> Thread.stop
> p "#{Thread.current} restarted"
> end
> }
>
> $stoppable << Thread.new {
> while sleep 1
> p "child is running"
> end
> }
>
> p "started"
> sleep 5
> p "stopping all"
> stop_all
> sleep 5
> p "starting all"
> start_all
> sleep 5
> p "exiting"
>
On second thought, this is actually just what I need, with a small
modification: only call set_trace_func when the request to stop comes
in, and then call set_trace_func(nil) when threads are restarted.
For example:
th = Thread.new do
loop do
sleep 0.1
puts "alive!"
end
end
sleep 0.3
puts "stopping"
stopper = proc {|event, file, line, id, binding, classname|
Thread.stop if Thread.current == th
}
set_trace_func stopper
sleep 1
puts "starting"
set_trace_func nil
th.wakeup
sleep 0.3
The output is:
alive!
alive!
stopping
starting
alive!
alive!
alive!
(There's about a 1 sec delay between the "stopping" and "starting"
lines, as desired.)
So, thanks for the suggestion, Daniel. I just didn't consider it closely
enough before, because I was scared away by set_trace_func.
--
vjoel : Joel VanderWerf : path berkeley edu : 510 665 3407