Forum: Ruby Re: Thread#stop

Announcement (2017-05-07): www.ruby-forum.com is now read-only since I unfortunately do not have the time to support and maintain the forum any more. Please see rubyonrails.org/community and ruby-lang.org/en/community for other Rails- und Ruby-related community platforms.
1c1e3bdfe006a22214102fcd6434a012?d=identicon&s=25 Daniel Sheppard (Guest)
on 2006-02-16 00:42
(Received via mailing list)
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"
47b1910084592eb77a032bc7d8d1a84e?d=identicon&s=25 Joel VanderWerf (Guest)
on 2006-02-16 00:57
(Received via mailing list)
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.

Nice, but I think set_trace_func is going to kill my app. Thanks anyway,
though.
47b1910084592eb77a032bc7d8d1a84e?d=identicon&s=25 Joel VanderWerf (Guest)
on 2006-02-19 01:00
(Received via mailing list)
Daniel Sheppard wrote:
> end
>         p "#{Thread.current} restarted"
> 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.
47b1910084592eb77a032bc7d8d1a84e?d=identicon&s=25 Joel VanderWerf (Guest)
on 2006-02-19 01:18
(Received via mailing list)
And with a little extra work, one can use this to approximate
Thread#backtrace as well as Thread#stop (neither of which exist):

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|
  if Thread.current == th
    puts caller.join("\n    from ")
    Thread.stop
  end
}
set_trace_func stopper

sleep 1

puts "starting"
set_trace_func nil
th.wakeup

sleep 0.3


alive!
alive!
stopping
thread-stop.rb:6
    from thread-stop.rb:6
    from thread-stop.rb:4
    from thread-stop.rb:3
starting
alive!
alive!
alive!



(This is only approximate because the thread isn't stopped until after
the interpreter finishes whatever current ruby primitive is evaluating,
but it's good enough for my purposes.)
This topic is locked and can not be replied to.