[lnkForumImage]
TotalShareware - Download Free Software

Confronta i prezzi di migliaia di prodotti.
Asp Forum
 Home | Login | Register | Search 


 

Forums >

comp.lang.ruby

Thread::list and GC

Ara.T.Howard

10/29/2004 4:43:00 AM

14 Answers

Bill Kelly

10/29/2004 5:29:00 AM

0

From: "Ara.T.Howard" <Ara.T.Howard@noaa.gov>
>
> 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

?


Regards,

Bill




Robert Klemme

10/29/2004 7:34:00 AM

0


"Bill Kelly" <billk@cts.com> schrieb im Newsbeitrag
news:003b01c4bd78$530e7c80$6442a8c0@musicbox...
> From: "Ara.T.Howard" <Ara.T.Howard@noaa.gov>
> >
> > 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

So you can safely walk through the array as long as you like. Threads are
GC'ed after termination:

09:32:51 [ruby]: ./th-list.rb
[#<Thread:0x100f59f8 run>]
.
[#<Thread:0x100e6878 sleep>, #<Thread:0x100f59f8 run>]
[#<Thread:0x100f59f8 run>]
[#<Thread:0x100f59f8 run>]
09:32:55 [ruby]: cat th-list.rb
#!/usr/bin/ruby

p Thread.list

Thread.new do
puts "."
sleep 1
end

p Thread.list
sleep 1
p Thread.list
GC.start
p Thread.list
09:32:57 [ruby]:

The std lib contains a class that helps with the termination of multiple
threads:
http://www.ruby-doc.org/stdlib/libdoc/thwait/rdoc/...

Kind regards

robert

Eric Hodel

10/29/2004 7:01:00 PM

0

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



Ara.T.Howard

10/29/2004 7:22:00 PM

0

Bill Kelly

10/29/2004 9:14:00 PM

0

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...


Regards,

Bill




Eric Hodel

10/29/2004 9:18:00 PM

0

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?

ThreadGroups allow you to do that:

$ ruby
t = Thread.new { sleep 4 }
tg = ThreadGroup.new
tg.add t
p tg.list
sleep 10
p tg.list
[#<Thread:0x1cb878 sleep>]
[]



Ara.T.Howard

10/29/2004 9:39:00 PM

0

Robert Klemme

10/30/2004 12:23:00 PM

0


"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.

Kind regards

robert


Eric Hodel

10/30/2004 7:06:00 PM

0

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.

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.

--
Eric Hodel - drbrain@segment7.net - http://se...
All messages signed with fingerprint:
FEC2 57F1 D465 EB15 5D6E 7C11 332A 551C 796C 9F04

Bill Kelly

10/31/2004 12:55:00 AM

0

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" ?


Regards,

Bill