semuel has asked for the wisdom of the Perl Monks concerning the following question:

Dear Monks, I am writing an embedded Perl program. The embedded module is suppose to return an object, (blessed hash ref, for example) and I use this object to make the calls.

Now came the requirement for threading. this said object creates threads as workers.
To my suprize, I found out that the object itself is being copied to the worker threads, and destroyed then they are destroyed.
How can it be? I scanned my code, and I don't keep this object ref inside Perl, but in SV* on the C side. I thought that it is completely safe there.
How do I protect my SVs so Perl won't duplicate them when it create a thread?
(in perl it's easy. just make sure it's not a global)

Thanks,
Shmuel.

Replies are listed 'Best First'.
Re: Protecting External Data?!
by plobsing (Friar) on Dec 20, 2007 at 01:16 UTC
    Have you incremented the refcount on the variable? If not, try SvREFCNT_inc(my_sv);
    Perl does see the variable when you use it to call methods. This in turn makes it vulnerable to garbage collection.
    As to how to prevent it from being garbage collected (permanently), I'm not certain, but you might be able to create an empty DESTROY method.UPDATE: won't work
    If you want something that perl won't garbage collect, create a circular reference.

      The DESTROY method is merely advisory. It is called when destruction is about to happen. It is possible for DESTROY to make new references to prevent an object from being destroyed.

      You're right about making sure the original hash had the REFCNT set high enough.

      ⠤⠤ ⠙⠊⠕⠞⠁⠇⠑⠧⠊

      You haven't understood me. it's not that I don't want it to be GCed. I don't want it to be duplicated in the first place.

      you see, if you do this in Perl:

      my $x = 5; sub ct { threads->create(\&worker); }
      then $x will be copied to the new thread. but if you do this:
      sub ct { my $x = 5; threads->create(\&worker); }
      $x won't be copied.

      I thought that if I keep my SV outside of Perl, it just won't be accessable and won't be copied. apperently I am wrong.
      So I need help protecting my SV against the almighty thread duplicator. how can I do it?

        perlmod has a nice description of how your modules can play nice with threads.
        It describes the CLONE_SKIP routine which you can add to your module to prevent cloning across threads.

        If you only want to not clone one of many instances, you could create a subclass Class::Foo::NoClone which is empty save for a sub CLONE_SKIP { 1 } and a @ISA = ('Class::Foo'); and rebless the specific instance into that.

        Also, are you sure that it won't clone the second $x? Its been a while since I've used threads. Where in the docs does it say that? I would assume they would be treated equally, both being lexical variables and all.

        Update: proof that the second $x is cloned
        use threads; use strict; use warnings; use PadWalker qw(peek_sub); sub thr { my $xref = peek_sub(\&run_test)->{'$x'}; print "\$xref in thr: $xref\n"; } sub run_test { my $x = 1; my $xref = \$x; print "\$xref before thr: $xref\n"; threads->create(\&thr)->join; $xref = \$x; print "\$xref after thr: $xref\n"; } run_test;
        Output (on perl v5.8.8 built for x86_64-linux-gnu-thread-multi):
        $xref before thr: SCALAR(0x6c51a0) $xref in thr: SCALAR(0x7584a0) $xref after thr: SCALAR(0x6c51a0)