develooper 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
========================================================================



nntp.perl.org: Perl Programming lists via nntp and http.
Comments to Ask Bjørn Hansen at ask@perl.org | Group listing | About