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

Greetings Monks,

I have recently started experimenting with threads and have the following problem. Whenever I try and share a scalar ref using a queue I can't access that reference in other parts of my code by storing it in a global variable. The problem is illustrated by the code below.

P.S There is a reason I am not passing the reference directly to the function instead (even though this does seem to work)
#!/usr/bin/env perl use strict; use threads; use Thread::Queue; my $q=Thread::Queue->new; my $thr=async { my $progref; sub ch { print "In ch \$progref=$progref\n"; #progref is still undefine +d (why?) $$progref=90; } $progref=$q->dequeue; #This seems to create a local $progref, but +it shouldn't! print "In main part of thread \$progref=$progref\n"; $$progref=30; #This is applied ch(); #This is ignored }; my $prog :shared; $q->enqueue(\$prog); sleep 2; print "$prog\n"; #Prints 30, not 90 $q->end; $thr->join;

Replies are listed 'Best First'.
Re: Threads and Shared Variables
by BrowserUk (Patriarch) on Jul 04, 2013 at 19:31 UTC

    Don't embed function definitions (eg. sub) inside other blocks.

    See For loop and Sub Routines for the same problem without threads.


    With the rise and rise of 'Social' network sites: 'Computers are making people easier to use everyday'
    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.
      Thanks, but I'm still unclear as to why this is happening. Since the $progref variable shares the same scrope with the sub, I don't understand why the sub can't see it. I've read the relevant section of perlsub, and as far as I can tell this should work.
        and as far as I can tell this should work.

        It doesn't. And it won't whether you understand it or not.

        In Perl: DO NOT DEFINE SUBROUTINES WITHIN NESTED SCOPES!

        Weird bugs happen whether threads are involved or not. And when threads are involved, they can be even weirder. So don't do it.

        I could probably eventually explain why it doesn't work, but then I would have to think about it and probably do some experiments. But as there is no good reason to declare subs in async blocks; and many good reasons not to, I cannot be bothered to work out what does or does not work.


        With the rise and rise of 'Social' network sites: 'Computers are making people easier to use everyday'
        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.
Re: Threads and Shared Variables
by roboticus (Chancellor) on Jul 04, 2013 at 19:42 UTC

    hermes1908:

    It will work if you move the definition of $progref and the ch subroutine outside of your async block:

    $ cat 1042506.pl #!/usr/bin/env perl use strict; use threads; use Thread::Queue; my $q=Thread::Queue->new; my $progref; my $thr=async { $progref=$q->dequeue; #This seems to create a local $progref, but +it shouldn't! print "In main part of thread \$progref=$progref\n"; $$progref=30; #This is applied ch(); #This is ignored }; my $prog :shared; $q->enqueue(\$prog); sleep 2; print "$prog\n"; #Prints 30, not 90 $q->end; $thr->join; sub ch { print "In ch \$progref=$progref\n"; #progref is still undefined (w +hy?) $$progref=90; } $ perl 1042506.pl In main part of thread $progref=SCALAR(0x84bfa60) In ch $progref=SCALAR(0x84bfa60) 90

    ...roboticus

    When your only tool is a hammer, all problems look like your thumb.

Re: Threads and Shared Variables
by Preceptor (Deacon) on Jul 04, 2013 at 19:31 UTC

    You declare 'my $progref' before the sub 'ch' and it's therefore in scope as a local variable (and is null). However you dequeue it _after_ you try and set it to 90. Which is why it doesn't work.

    IT's only after that $progref = $q -> dequeue() that 'progref' is a reference to the right memory location.

    I'm somewhat confused as to why you're trying to pass references to shared variables in the first place though. What are you trying to accomplish?

    Update

    Looks like BrowserUk is on target - it's to do with subs in sub code blocks, rather than threads.