i have a program i'd like to exit gracefully on certain signals. the code
spawns many threads which are never joined. however, when signaled i want to
finished and pending threads before exiting - something like
if $signaled
Thread::list.each do |t|
next if Thread::current == t
begin
t.join
rescue => e
warn{ e }
end
end
end
i'm wondering:
if i spawn threads and never join them - will Thread::list grow without
bound?
are there any issues with iterating Thread::list - since this list is
obviously changing all the time in this code (new Threads started)
cheers.
-a
···
--
EMAIL :: Ara [dot] T [dot] Howard [at] noaa [dot] gov
PHONE :: 303.497.6469
When you do something, you should burn yourself completely, like a good
bonfire, leaving no trace of yourself. --Shunryu Suzuki
Have you seen the ThreadGroup class? A thread can only live in one ThreadGroup, so you can create a ThreadGroup for spawned threads, add the spawned threads to that ThreadGroup, then walk the ThreadGroup's list on shutdown. This way you don't have to worry about killing Thread.current
···
On Oct 28, 2004, at 9:53 PM, Ara.T.Howard wrote:
i have a program i'd like to exit gracefully on certain signals. the code spawns many threads which are never joined. however, when signaled i want to finished and pending threads before exiting - something like
if $signaled
Thread::list.each do |t|
next if Thread::current == t
begin
t.join
rescue => e
warn{ e }
end
end
end
i'm wondering:
if i spawn threads and never join them - will Thread::list grow without bound?
are there any issues with iterating Thread::list - since this list is obviously changing all the time in this code (new Threads started)
i did look at that - however i'm worried that having a reference to the thread
will maintain a reference that will keep it from getting GC'd. see, i
normally simply spawn the threads and forget about them - it's only for
catching signals that i need to shut down any running threads. does the above
sound accurate?
-a
···
On Sat, 30 Oct 2004, Eric Hodel wrote:
On Oct 28, 2004, at 9:53 PM, Ara.T.Howard wrote:
i have a program i'd like to exit gracefully on certain signals. the
code spawns many threads which are never joined. however, when
signaled i want to finished and pending threads before exiting -
something like
if $signaled
Thread::list.each do |t|
next if Thread::current == t
begin
t.join
rescue => e
warn{ e }
end
end
end
i'm wondering:
if i spawn threads and never join them - will Thread::list grow
without bound?
are there any issues with iterating Thread::list - since this list is
obviously changing all the time in this code (new Threads started)
Have you seen the ThreadGroup class? A thread can only live in one
ThreadGroup, so you can create a ThreadGroup for spawned threads, add
the spawned threads to that ThreadGroup, then walk the ThreadGroup's
list on shutdown. This way you don't have to worry about killing
Thread.current
--
EMAIL :: Ara [dot] T [dot] Howard [at] noaa [dot] gov
PHONE :: 303.497.6469
When you do something, you should burn yourself completely, like a good
bonfire, leaving no trace of yourself. --Shunryu Suzuki
> > are there any issues with iterating Thread::list - since this list is
> > obviously changing all the time in this code (new Threads started)
>
> Maybe,
>
> while th = Thread::list.find {|t| t != Thread.current}
> begin
> th.join
> rescue => e
> warn{ e }
> end
> end
This does not make a difference as Thread.list() creates a new array on
each invokation:
The OP mentioned the possibility of new threads being created
all the while. I had read that as the OP wanting to ensure
that we would handle the joining any new threads that may have
become spawned while we were trying to shut down others.
So my proposed solution was intended to loop until all threads
were truly joined...
$ ruby
t = Thread.new { sleep 4 }
tg = ThreadGroup.new
tg.add t
p tg.list
sleep 10
p tg.list
[#<Thread:0x1cb878 sleep>]
···
On Oct 29, 2004, at 12:33 PM, Ara.T.Howard@noaa.gov wrote:
On Sat, 30 Oct 2004, Eric Hodel wrote:
On Oct 28, 2004, at 9:53 PM, Ara.T.Howard wrote:
i have a program i'd like to exit gracefully on certain signals. the
code spawns many threads which are never joined. however, when
signaled i want to finished and pending threads before exiting -
something like
if $signaled
Thread::list.each do |t|
next if Thread::current == t
begin
t.join
rescue => e
warn{ e }
end
end
end
i'm wondering:
if i spawn threads and never join them - will Thread::list grow
without bound?
are there any issues with iterating Thread::list - since this list is
obviously changing all the time in this code (new Threads started)
Have you seen the ThreadGroup class? A thread can only live in one
ThreadGroup, so you can create a ThreadGroup for spawned threads, add
the spawned threads to that ThreadGroup, then walk the ThreadGroup's
list on shutdown. This way you don't have to worry about killing
Thread.current
i did look at that - however i'm worried that having a reference to the thread
will maintain a reference that will keep it from getting GC'd. see, i
normally simply spawn the threads and forget about them - it's only for
catching signals that i need to shut down any running threads. does the above
sound accurate?
are there any issues with iterating Thread::list - since this list is
obviously changing all the time in this code (new Threads started)
Maybe,
while th = Thread::list.find {|t| t != Thread.current}
begin
th.join
rescue => e
warn{ e }
end
end
This does not make a difference as Thread.list() creates a new array on
each invokation:
Thread.list().id
=> 135026036
Thread.list().id
=> 135022100
Thread.list().id
=> 135018212
The OP mentioned the possibility of new threads being created
all the while. I had read that as the OP wanting to ensure
that we would handle the joining any new threads that may have
become spawned while we were trying to shut down others.
So my proposed solution was intended to loop until all threads
were truly joined...
--
EMAIL :: Ara [dot] T [dot] Howard [at] noaa [dot] gov
PHONE :: 303.497.6469
When you do something, you should burn yourself completely, like a good
bonfire, leaving no trace of yourself. --Shunryu Suzuki
"Bill Kelly" <billk@cts.com> schrieb im Newsbeitrag news:015a01c4bdfc$44198d30$6442a8c0@musicbox...
From: "Robert Klemme" <bob.news@gmx.net>
> > are there any issues with iterating Thread::list - since this list > > is
> > obviously changing all the time in this code (new Threads started)
>
> Maybe,
>
> while th = Thread::list.find {|t| t != Thread.current}
> begin
> th.join
> rescue => e
> warn{ e }
> end
> end
This does not make a difference as Thread.list() creates a new array on
each invokation:
The OP mentioned the possibility of new threads being created
all the while. I had read that as the OP wanting to ensure
that we would handle the joining any new threads that may have
become spawned while we were trying to shut down others.
So my proposed solution was intended to loop until all threads
were truly joined...
Ooops, sorry I overlooked the loop. I concetrated on the iteration with each vs. find.
But: this solution has a problem. You can't ensure that it terminates. You will have to set some kind of flag somewhere that no new threads are created anyway. *If* you do that, you can just as easily wait once for all currently running threads *after* the flag has been set because you know there will be no new threads.
It will prevent the scheduling of other threads. Note that starting a
new thread can switch to that thread, so be careful.
···
Robert Klemme (bob.news@gmx.net) wrote:
"Bill Kelly" <billk@cts.com> schrieb im Newsbeitrag
news:015a01c4bdfc$44198d30$6442a8c0@musicbox...
>From: "Robert Klemme" <bob.news@gmx.net>
>>> > are there any issues with iterating Thread::list - since this list
>>> > is
>>> > obviously changing all the time in this code (new Threads started)
>>>
>>> Maybe,
>>>
>>> while th = Thread::list.find {|t| t != Thread.current}
>>> begin
>>> th.join
>>> rescue => e
>>> warn{ e }
>>> end
>>> end
>>
>>This does not make a difference as Thread.list() creates a new array on
>>each invokation:
>>
>>>> Thread.list().id
>>=> 135026036
>>>> Thread.list().id
>>=> 135022100
>>>> Thread.list().id
>>=> 135018212
>
>The OP mentioned the possibility of new threads being created
>all the while. I had read that as the OP wanting to ensure
>that we would handle the joining any new threads that may have
>become spawned while we were trying to shut down others.
>So my proposed solution was intended to loop until all threads
>were truly joined...
Ooops, sorry I overlooked the loop. I concetrated on the iteration with
each vs. find.
But: this solution has a problem. You can't ensure that it terminates.
You will have to set some kind of flag somewhere that no new threads are
created anyway. *If* you do that, you can just as easily wait once for all
currently running threads *after* the flag has been set because you know
there will be no new threads.
--
Eric Hodel - drbrain@segment7.net - http://segment7.net
All messages signed with fingerprint:
FEC2 57F1 D465 EB15 5D6E 7C11 332A 551C 796C 9F04
>> > while th = Thread::list.find {|t| t != Thread.current}
>> > begin
>> > th.join
>> > rescue => e
>> > warn{ e }
>> > end
>> > end
But: this solution has a problem. You can't ensure that it terminates. You
will have to set some kind of flag somewhere that no new threads are created
anyway. *If* you do that, you can just as easily wait once for all
currently running threads *after* the flag has been set because you know
there will be no new threads.
I did think about that, whether it would terminate... But I'd
guessed that practically speaking the only scenario in which it
wouldn't terminate is if the threads we're trying to join are
themselves just spawning new threads like crazy. Kind of like
a fork() bomb, but with threads...
I thought about making it fancier with raising our own
Thread priority, and/or using Thread.critical... But I was
guessing that in a reasonably well-behaved system, the liklihood
of the above code not terminating was pretty much nil. . . .
So I was betting we wouldn't need to worry about it. Does it
seem the above would be likely to not terminate outside of
extreme cases like a "fork() bomb with threads" ?
"Eric Hodel" <drbrain@segment7.net> schrieb im Newsbeitrag news:20041030190559.GB93473@segment7.net...
> But: this solution has a problem. You can't ensure that it terminates.
> You will have to set some kind of flag somewhere that no new threads are
> created anyway. *If* you do that, you can just as easily wait once for > all
> currently running threads *after* the flag has been set because you know
> there will be no new threads.
That flag is Thread.critical = true
It will prevent the scheduling of other threads. Note that starting a
new thread can switch to that thread, so be careful.
That's the wrong flag. This just prevents scheduling of threads on the thread scheduler level. But what you really want in this scenario is a flag that tells the part of the application that creates new threads again and again to not do this any more. If you use Thread.critical for this you could end up joining a thread that will not be scheduled and all the work that has to be done (i.e. all threads that are running and need to be terminated) will not be done; worse than that the process might freeze and not terminate.
Note: it *might* work, but IMHO it's the wrong hammer.
"Bill Kelly" <billk@cts.com> schrieb im Newsbeitrag news:024d01c4bee4$5c87c880$6442a8c0@musicbox...
From: "Robert Klemme" <bob.news@gmx.net>
>> > while th = Thread::list.find {|t| t != Thread.current}
>> > begin
>> > th.join
>> > rescue => e
>> > warn{ e }
>> > end
>> > end
But: this solution has a problem. You can't ensure that it terminates. You
will have to set some kind of flag somewhere that no new threads are created
anyway. *If* you do that, you can just as easily wait once for all
currently running threads *after* the flag has been set because you know
there will be no new threads.
I did think about that, whether it would terminate... But I'd
guessed that practically speaking the only scenario in which it
wouldn't terminate is if the threads we're trying to join are
themselves just spawning new threads like crazy. Kind of like
a fork() bomb, but with threads...
I thought about making it fancier with raising our own
Thread priority, and/or using Thread.critical... But I was
guessing that in a reasonably well-behaved system, the liklihood
of the above code not terminating was pretty much nil. . . .
So I was betting we wouldn't need to worry about it. Does it
seem the above would be likely to not terminate outside of
extreme cases like a "fork() bomb with threads" ?
Well, I don't know the rest of your application. The crucial part is IMHO who creates all those threads. In a common TCPServer situation where one thread just waits for a connection and then fires off a new thread for each session, you would want to make sure that this does not happen any more once the process should terminate (notified via a signal, a message via thread or whatever). IMHO it's the cleanest solution to record this overall application state ("shutdown in progess") somewhere in order to react properly on this. Once this has happened you only need to iterate and join once through all running threads and that's it. It's the cleanest application design which does not leave any holes for bugs sneaking in when you install that application on another machine with other performance characteristics. But as I said, it depends on your overall application architecture.
almost exactly what i'm doing... basically i set a global variable when a
signal is caught and all parts of the the code respect this variable at the
appropriate time.
-a
···
On Sun, 31 Oct 2004, Robert Klemme wrote:
Well, I don't know the rest of your application. The crucial part is IMHO
who creates all those threads. In a common TCPServer situation where one
thread just waits for a connection and then fires off a new thread for each
session, you would want to make sure that this does not happen any more once
the process should terminate (notified via a signal, a message via thread or
whatever). IMHO it's the cleanest solution to record this overall
application state ("shutdown in progess") somewhere in order to react
properly on this. Once this has happened you only need to iterate and join
once through all running threads and that's it. It's the cleanest
application design which does not leave any holes for bugs sneaking in when
you install that application on another machine with other performance
characteristics. But as I said, it depends on your overall application
architecture.
--
EMAIL :: Ara [dot] T [dot] Howard [at] noaa [dot] gov
PHONE :: 303.497.6469
When you do something, you should burn yourself completely, like a good
bonfire, leaving no trace of yourself. --Shunryu Suzuki
I also forgot, setting Thread.critical to true, then joining another
thread may not resume the first thread...
···
Robert Klemme (bob.news@gmx.net) wrote:
"Eric Hodel" <drbrain@segment7.net> schrieb im Newsbeitrag
news:20041030190559.GB93473@segment7.net...
>> But: this solution has a problem. You can't ensure that it terminates.
>> You will have to set some kind of flag somewhere that no new threads are
>> created anyway. *If* you do that, you can just as easily wait once for
>> all
>> currently running threads *after* the flag has been set because you know
>> there will be no new threads.
>
>That flag is Thread.critical = true
>
>It will prevent the scheduling of other threads. Note that starting a
>new thread can switch to that thread, so be careful.
That's the wrong flag. This just prevents scheduling of threads on the
thread scheduler level. But what you really want in this scenario is a
flag that tells the part of the application that creates new threads again
and again to not do this any more. If you use Thread.critical for this you
could end up joining a thread that will not be scheduled and all the work
that has to be done (i.e. all threads that are running and need to be
terminated) will not be done; worse than that the process might freeze and
not terminate.
Note: it *might* work, but IMHO it's the wrong hammer.
--
Eric Hodel - drbrain@segment7.net - http://segment7.net
All messages signed with fingerprint:
FEC2 57F1 D465 EB15 5D6E 7C11 332A 551C 796C 9F04