in reply to Re^4: CLONE/DESTROY want work at all??
in thread CLONE/DESTROY want work at all??

Try the following.

Make each shared object keep track of how much it is used. In CLONE, increment the usage of each object that the thread will actually use. In DESTROY, decrement the usage of each object that the thread incremented. The key is that you have to decrement all of the things that you increment.

This should work much, much better than having each thread increment everything, then only decrement itself. Which is what your code currently does.

That said, I would personally advocate avoiding using threads unless you absolutely need to. Threads are always a huge complication, and I'm a big advocate of trying the simplest thing that could possibly work.

Replies are listed 'Best First'.
Re^6: CLONE/DESTROY want work at all??
by BrowserUk (Patriarch) on May 22, 2009 at 19:12 UTC
    Threads are always a huge complication, ...

    ... "Perl is always slow"; "football fans are always hooligans"; "blonds are always dumb"; and "mindless generalisations are always pointless".

    One of the above is true.


    Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
    "Science is about questioning the status quo. Questioning authority".
    In the absence of evidence, opinion is indistinguishable from prejudice.
      How is having a computer doing 2 things at once not more complicated than having it do 1? Furthermore figuring out the failure modes generally involves figuring out sequences of different threads hitting specific interactions.

      Threads are useful in figuring out how to use the maximum CPU power you can, and for solving latency issues. Threads are sometimes the simplest way of coming up with a solution that does what you want and addresses those issues. In those cases it is appropriate to use threads.

      But even in those situations the presence of threads is a complication in the code, and many (probably most) programmers are poorly equipped to properly deal with them. So I'm never going to suggest a multi-threaded solution unless there is a specific reason to think that they address a real problem which you have.

Re^6: CLONE/DESTROY want work at all??
by spacepille (Acolyte) on May 22, 2009 at 21:27 UTC
    That said, I would personally advocate avoiding using threads unless you absolutely need to.

    Most of my programs include server and other working threads.

    Make each shared object keep track of how much it is used. In CLONE, increment the usage of each object that the thread will actually use. In DESTROY, decrement the usage of each object that the thread incremented. The key is that you have to decrement all of the things that you increment.

    I tried it out, but it doesn't seem to be working better.

    Threads are always a huge complication

    Looks like you are right. The code below could work better. But... either Perl crashes or threads don't finish anymore. Very strange.

    #!/usr/local/bin/perl use threads; use Time::HiRes qw/usleep/; while( 1 ) { my $class = Class->new(); threads->create( \&thread_sub, $class, 0 ); usleep 200_000; } sub thread_sub { my( $class, $level ) = @_; print "THREAD ", threads->self->tid, ", $level running\n"; threads->create( \&thread_sub, $class, $level + 1 ) unless $level; usleep 400_000; print "THREAD ", threads->self->tid, ", $level finished\n"; threads->self->detach; } 1; package Class; use threads::shared; our %MY_CXT : shared = (); our $CXT_ID : shared = 0; sub new { my $class = shift; my $this = {}; $this->{'shared'} = &share( {} ), $this->{'shared'}{'refcnt'} = 1; $this->{'shared'}{'tid'} = threads->self->tid; $this->{'shared'}{'clone'} = 1; lock( %MY_CXT ); $this->{'id'} = ++ $CXT_ID; $MY_CXT{$this->{'id'}} = $this->{'shared'}; bless $this, $class; } sub CLONE { lock( %MY_CXT ); while( my( $k, $v ) = each %MY_CXT ) { # do not CLONE anymore when it's destroyed in the main thread $v->{'refcnt'} ++ if $v->{'clone'}; print "CLONE: id $k, refcnt $v->{'refcnt'}\n"; } } sub DESTROY { my $this = shift; my $shared = $this->{'shared'}; if( $shared->{'tid'} == threads->self->tid ) { # disable futher CLONEs $shared->{'clone'} = 0; # refcnt must decrement twice ? $shared->{'refcnt'} --; } $shared->{'refcnt'} --; print "DESTROY: id $this->{'id'}, refcnt $shared->{'refcnt'}\n"; if( $shared->{'refcnt'} <= 0 ) { lock( %MY_CXT ); # should not happen warn "already destroyed!!!" unless $MY_CXT{$this->{'id'}}; delete $MY_CXT{$this->{'id'}}; } } 1;