Front page | perl.perl5.porters |
Postings from February 2000
threads and reference counts
From:
Lincoln Stein
Date:
February 22, 2000 14:16
Subject:
threads and reference counts
Message ID:
200002222216.RAA22865@formaggio.cshl.org
Hi Dan,
Is there something about threading that increases the reference counts
of objects? In the little test below, I create an object twice. In
the first instance, I create it and immediately undef it, triggering
its DESTROY method as I'm expecting.
In the second instance, I create the object, launch a thread that
involves the object, and then let the thread terminate. Now when I
undef the object, DESTROY isn't called until sometime later during
global garbage collection.
Lincoln
% ./threadtest.pl
creating new object Threaded=HASH(0x80f35c0) at ./threadtest.pl line 5.
undefing it -- should DESTROY at ./threadtest.pl line 6.
DESTROY Threaded=HASH(0x80f35c0) at ./threadtest.pl line 44.
creating new object Threaded=HASH(0x80f35c0) at ./threadtest.pl line 10.
Thread=SCALAR(0x8119674) at ./threadtest.pl line 32.
setting done flag at ./threadtest.pl line 13.
_loop() is done
undefing it -- should DESTROY at ./threadtest.pl line 17.
all done at ./threadtest.pl line 20.
DESTROY Threaded=HASH(0x80f35c0) at ./threadtest.pl line 44 during global destruction.
#!/usr/bin/perl
use Thread;
warn "creating new object ",$h = new Threaded;
warn "undefing it -- should DESTROY";
undef $h;
sleep 5;
warn "creating new object ",$h = new Threaded;
$h->launch_thread;
sleep 3;
warn "setting done flag";
$h->{done}++;
sleep 3;
warn "undefing it -- should DESTROY";
undef $h;
sleep 5;
warn "all done";
package Threaded;
sub new {
my $pack = shift;
return bless {done=>0},$pack;
}
sub launch_thread {
my $self = shift;
$self->{done} = 0;
warn my $t = Thread->new(\&_loop,$self);
$t->detach;
}
sub _loop {
my $self = shift;
while (!$self->{done}) {
sleep 1;
}
warn "_loop() is done\n";
}
sub DESTROY { warn "DESTROY ",shift }
Dan Sugalski writes:
> At 12:48 PM 2/16/00 -0500, Lincoln Stein wrote:
> >Hi Dan,
> >
> >Thanks for your continuing clarifications. Is the correct idiom for
> >blocking threads?
> >
> > select() with a timeout of a second or so
> > examine a global "abort" variable and maybe abort
> > read data
>
> Yep. Or as correct as can be managed with threads at the moment.
>
> > > It's cond_signal and cond_broadcast, FWIW--cond_wait puts the thread to
> > sleep.
> >
> > > The docs are kinda spotty (my fault), so there's some confusion. The
> > > important bit when dealing with conditions isn't the signalling and
> > > sleeping you get with the cond_* functions, it's the contents of the
> > > condition variable itself. You can think of them like:
> >
> > > cond_wait: I'm sleeping until the condition changes
> > > cond_signal: Nudge one thread that the condition's changed
> > > cond_broadcast: Nudge all the threads that the condition's changed
> >
> >Sorry - I screwed up the question. I meant to ask the difference
> >between cond_signal and cond_broadcast of course. But the question I
> >had is still the same. Both cond_signal and cond_broadcast will wake
> >up any threads that are cond_waiting on a condition variable.
> >According to the Pthreads docs, before cond_wait returns it reacquires
> >the lock on the condition variable. So I imagine the effect of
> >cond_broadcast() is waking up a lot of threads and then only one of
> >them getting the lock so that the rest go to sleep -- rather
> >pointless. Or do they not get the lock? The
> >cond_wait()/cond_signal() combo certainly seems to guarantee that the
> >cond_wait-ing thread gets the lock again.
>
> Well, it depends on the condition.
>
> Let's say, for example, that the condition you're waiting on is a count of
> things in a queue, and you've got a bunch of threads willing and able to
> take things out of the queue and process them. (If, for example, you've got
> a multiprocessor machine and can reasonably process more than one thing at
> once)
>
> All those threads go into cond_wait if the condition is zero.
>
> At some point a source thread snags a lock on the condition variable,
> stuffs, say, three things in the queue, and cond_broadcasts.
>
> All the waiting threads wake up and attempt to lock the condition. They
> each, in turn, get the lock, check to make sure the condition's still true
> and, if it is, snag a single thing from the queue and decrement the
> condition. Then they release the lock and process their element. The code
> may look like:
>
> while (1) {
> my $thingie;
> {
> lock $cond;
> cond_wait $cond until $cond;
> $cond--;
> $thingie = dequeue($queue);
> }
> process($thingie);
> }
>
> So basically cond_broadcast is useful when the condition you satisfy can
> potentially affect multiple threads, and cond_signal when you know it's
> only one.
>
> The Thread::Queue module uses this--when a thread tries to dequeue an empty
> queue it cond_waits, while enqueueing cond_broadcasts. Makes sense, since
> you can potentially be enqueueing a half-zillion things, while dequeue
> removes only one.
>
> Dan
>
> --------------------------------------"it's like this"-------------------
> Dan Sugalski even samurai
> dan@sidhe.org have teddy bears and even
> teddy bears get drunk
--
========================================================================
Lincoln D. Stein Cold Spring Harbor Laboratory
lstein@cshl.org Cold Spring Harbor, NY
========================================================================
-
threads and reference counts
by Lincoln Stein