Beefy Boxes and Bandwidth Generously Provided by pair Networks
Think about Loose Coupling
 
PerlMonks  

How to avoid extra DESTROY calls in multi-threaded program?

by jwu (Novice)
on Dec 21, 2006 at 17:13 UTC ( #591132=perlquestion: print w/ replies, xml ) Need Help??
jwu has asked for the wisdom of the Perl Monks concerning the following question:

Hi, I have this strange question while doing some multi-threaded programming.

The code below output :

thread start Destroy A=HASH(0x10124254) thread start Destroy A=HASH(0x101254f4) Destroy A=HASH(0x1002f054)
with two more DESTROY calls, how can I avoid them? I am using ActiveState 5.8.4 810 on Win XP

Also, if I use  my $a : shared = A->new() then there will be another two more DESTROY calls.

use threads; use threads::shared; { package A; use threads; use threads::shared; sub new { my $class = shift; my $self = &share({}); return bless $self, $class; } sub get_s { } sub DESTROY { print "Destroy $_[0]\n"; } } my $a = &share(A->new()); for (1..2) { async { print "thread start\n"; $a->get_s(); }->join(); }
Thanks.

Comment on How to avoid extra DESTROY calls in multi-threaded program?
Select or Download Code
Re: How to avoid extra DESTROY calls in multi-threaded program?
by SFLEX (Chaplain) on Dec 21, 2006 at 18:19 UTC
    those errors "HASH(0x101254f4)" is telling you the variable your printing is realy a hash.

    "If a reference is used in a context where a string is expected, then the ref function is called automatically to produce the expected string, and a unique hexadecimal value (the internal memory address of the thing being referred to) is appended. That means that printing out a reference:" - Bless My Referents

    Good Luck!

    Updated: :s

      I really don't think this is helpful advice. All of the output I saw contained the default stringification of blessed references.

        I agree.
Re: How to avoid extra DESTROY calls in multi-threaded program?
by ivancho (Hermit) on Dec 21, 2006 at 18:23 UTC
    not a threads expert, but it looks to me like on Win32, sharing is acheved by cloning the object several times to pass to different threads.. so if you try:
    use threads; use threads::shared; { package A; use threads; use threads::shared; sub new { my $class = shift; my $self = &share({}); print "Created $class at $self\n"; return bless $self, $class; } sub get_s { } sub DESTROY { print "Destroy $_[0]\n"; } } my $a :shared; $a = A->new(); for (1..2) { async { print "thread start\n"; $a->get_s(); }->join(); }

    you'll see that only the last DESTROY is from an object created by 'new'..
    P:\bin>perl threads_test.cgi Created A at HASH(0x225800) thread start Destroy A=HASH(0x1e07d9c) thread start Destroy A=HASH(0x1dbba9c) Destroy A=HASH(0x225800)

    Try an inside-out approach:
    in 'new', register the created $self in a static hash( ie,
    package A; our %created_objs : unique; sub new { ... bless $self, $class; $created_objs{ $self } = 1; return $self; }
    and then in DESTROY first check that your object is an original :
    sub DESTROY { my $self = shift; if ($created_objs{$self}) { # do my DESTROY stuff delete $created_objs{ $self }; } }
    update: added a little code to show that registering must happen after the blessing
    update 2: to be perfectly safe, you probably want instead to have a private attribute which is your key in the static hash.. otherwise if your object gets reblessed, you're screwed - "$self" will change
Re: How to avoid extra DESTROY calls in multi-threaded program?
by renodino (Curate) on Dec 21, 2006 at 19:10 UTC
    with two more DESTROY calls, how can I avoid them?

    Strictly speaking, you can't. Each thread(including your root thread) has its own private "proxy" copy of the object, which is magically tied to the real object stored in a global shared interpretter context inside threads::shared. When each thread exits, all its object will get DESTROY'd, including the proxies.

    I'd suggest you include a member in the object thats the TID of the creator thread to indicate whether the current thread should really DESTROY anything or not. In general, only the object creator should do a full DESTROY. So just add a simple test:

    sub new { ...your code... $self->{_creator_tid} = threads->tid(); return bless $self, $class; } sub DESTROY { print "Destroy $_[0]\n" if (threads->tid() == $_[0]->{_creator_tid}); }
    Note that whether you can actually ignore DESTROY in child threads is an app-specific issue; you may need to do some per-thread cleanup on exit.

    Perl Contrarian & SQL fanboy

Log In?
Username:
Password:

What's my password?
Create A New User
Node Status?
node history
Node Type: perlquestion [id://591132]
Approved by Corion
help
Chatterbox?
and the web crawler heard nothing...

How do I use this? | Other CB clients
Other Users?
Others imbibing at the Monastery: (11)
As of 2014-09-18 20:29 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    How do you remember the number of days in each month?











    Results (124 votes), past polls