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

I am trying to use objects and threads together and I face a problem. Every object of mine starts a thread. The thread must share one variable with the object's main thread.

When not using objects and you wish to share a variable between threads, you just declare it:

my $var : shared = 1;

However, when using objects... This doesn't work:

$self->{var} : shared = 1;

How do I declare an object variable as shared? Help...?

Replies are listed 'Best First'.
Re: OO and Threads conflict?
by RMGir (Prior) on Sep 21, 2002 at 10:47 UTC
    What you need is at least partially an adaptation of Inside-out objects.
    # note the package level shared hash; this will store the # actual values of the active attribute. my %active : shared; # CONSTRUCTOR sub new { local *IN; my $self = {}; $self->{active} = \$active{$self} = 1; # This vari +able must be shared between threads. $self->{in} = undef; $self->{thread} = undef; open(*IN, "a_program" ) or ${$self->{active}} = 0; $self->{in} = *IN; $self->{thread} = threads->new(\&reader, $self); # Start thread bless($self); return $self; }
    Then you can access the shared value as ${$self->{active}}, or as $active{$self} if you're in the package...

    At least, I think this will work; it would be nice if I had 5.8.0 installed here to test it :)
    --
    Mike

Re: OO and Threads conflict?
by Anonymous Monk on Sep 20, 2002 at 23:29 UTC
    To clarify, I am showing an example of what I am trying to do, trimmed down and not functional. As you can see, it's a simple object with a separate thread that keeps reading the output from a program. The thread should exit when the variable $self->{active} turns false, for example by running the method 'stop'.

    package Thingee; use threads; use threads::shared; # CONSTRUCTOR sub new { local *IN; my $self = {}; $self->{active} : shared = 1; # SYNTAX ERROR HERE # This variable must be shared between # threads. $self->{in} = undef; $self->{thread} = undef; open(*IN, "a_program" ) or $self->{active} = 0; $self->{in} = *IN; $self->{thread} = threads->new(\&reader, $self); # Start thread bless($self); return $self; } # READER (Thread) sub reader { my $self = shift; my $fh = $self->{in}; my $line; while ( $self->{active} ) { $line = <$fh>; print "> $line\n"; } } # METHOD sub stop { my $self = shift; $self->{active} = 0; } # RETURN TRUE FOR THE USE 1;
Re: OO and Threads conflict?
by runrig (Abbot) on Sep 20, 2002 at 23:59 UTC
    However, when using objects... This doesn't work: $self->{var} : shared = 1;

    Consider me a threading newbie, but is there any reason you can't just share "$self". Or maybe this:

    my $self = {}; my $var : shared = 1; $self->{var} = \$var; #(Update)Then later to get or set $var: ${$self->{var}} = 0; ... while (${$self->{var}) { ...
      Yes. Trying to share $self as such;
           my $self : shared = {};
      results in an error:
           Invalid value for shared scalar at...

      As for the suggested code snippet, I still end up with the thread having it's own private copy of the $self->{var}. The main thread and the 'loose thread' still do not share any data.
        As for the suggested code snippet, I still end up with the thread having it's own private copy of the $self->{var}.

        I can see each process having its own copy of $self->{var}, but what about ${$self->{var}} ?? They should be referring to the same shared data, no?

        Gee... Thanks. =)

        When referring to them as ${$self->{var}] it DOES work. The problem is now officially solved. Now, would you please explain to me what you did, because I am feeling abit lost here. =)

        And... This doesn't mean that the data is shared between all instances off the class, right?
Re: OO and Threads conflict?
by djantzen (Priest) on Sep 20, 2002 at 22:06 UTC

    I'd hazard a guess that it's the difference between sharing a variable and sharing a value, where in the former case you've actually got a label by which to refer to a thing and in the latter you're doing a hash lookup and returning a string or integer or something. Does it work if you say  $self->{var} = $var; $self->{var} : shared = 1; ?

      Nope...

      $self->{var} : shared = 1; gives a syntax error. Doesn't matter what you write before it. It's still a syntax error.

        What about declaring the variable shared before assigning it to your hash, as in my $var : shared = 1; $self->{var} = \$var. Although on further consideration I wonder if it might be better to be using a package variable via our or use vars since it looks like what you want is a 'static' variable i.e., one shared by all instances of a class, and these constructs provide that behavior. I don't have threads compiled so I can't test this, but this might work:

        package OOThread; use threads; our static_var : shared = 1; # may not be necessary to explicitly shar +e 'our' variables sub new {...} ...

Re: OO and Threads conflict?
by beamsack (Scribe) on Sep 21, 2002 at 18:55 UTC
    I am betting that every thread created in this example already shares a variable with the main thread - the object itself!

    $self->{thread} = threads->new(\&reader, $self);      # Start thread

    • The object starts the thread, passing function reader as parameter 1 - the thread proc
    • $self (i.e. the object) is passed as parameter 2
    Therefore any functionality of the object should be available to the thread.

    I think the concept of wrapping threads in objects is a little confusing and dangerous. A thread proc is different than a object function - it represents a new path of execution.

    It may be cool to wrap a thread in an object but objects go out scope - $self will become invalid if the object goes out scope before thread function reader exits.

      $self will become invalid if the object goes out scope before thread function reader exits.
      (Disclaimer: I'm not sure I'm following what you're saying.) That said, this ain't C++ so $self is a reference, not a pointer, and unlike pointers, references are smart. If the variable goes out of scope in one place but is also referenced from another scope, it won't become "invalid". (What's that, anyway? Do you mean undef? Dangling pointer (no such thing in Perl)? Or something else?) You might want to look into closures.

      Makeshifts last the longest.

        Thanks Aristotle I will look into closures.

        I usually test my assumptions but I'm stuck working today.

        I have spent too many years chasing down pointer problems in C/C++ - this is for sure, point taken.
        I am making a dangerous assumption that the function reader is equivalent to a thread proc in C/C++. If so, it is basically just like the main() function in C. It will need to return before dying. If I pass an object into a thread proc that some how controls the life-time of the thread, I hope that the object's life-time exceeds that of the thread.
        If the object ceases to exist before the thread terminates - how will I control the thread.

        Threads can cause wickedly interesting problems!!!