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

Hello all! I would like to run two subroutines in parallel. Ideally, what should happen is, both subroutines should be executed in parallel. listen() should continuously listen for a stop signal (that will be sent in from another process. I would later like to use a named pipe for this) and run() should continuously run its own tasks . Each should be oblivious to what the other is doing unless a stop signal is sent and listen() is able to pick up on it. Once stop is heard, listen should relay to run() to stop what its doing and exit. At the moment, I just have listen() counting down to simulate a "signal" sent. I'm trying to achieve this using threading, but from the output, it does not seem like the two subroutines are truly being executed in parallel which I require. It appears to me that run() is being ran first and for a good amount of time before listen() is executed. How can I make this work?
#!/usr/bin/perl use threads; use threads::shared; my ($stop) : shared; $stop = 0; my $running_t = threads->new(\&run, 2); my $listening_t = threads->new(\&listen, 1); sub listen { my $cd = 10; while ($cd > 0) { print "waiting ... $cd\n"; $cd--; } print "SIGNAL HEARD! STOP RUN()\n"; $stop = 1; } sub run { while(!$stop) { print "still running...\n"; } print "SIGNAL HEARD! STOPPING" } my @running_ret = $running_t->join; my @listening_ret = $listening_t->join; print "listen: @listening_ret\n"; print "run: @running_ret\n";
Output:
still running... still running... still running... still running... still running... still running... still running... still running... still running... still running... still running... still running... still running... still running... still running... still running... . . # Note: truncated due to size of output . still running... still running... still running... still running... still running... still running... still running... still running... still running... still running... still running... still running... still running... still running... still running... still running... still running... still running... still running... still running... still running... still running... still running... still running... still running... waiting ... 10 still running... still running... waiting ... 9 still running... waiting ... 8 still running... waiting ... 7 still running... waiting ... 6 still running... waiting ... 5 still running... waiting ... 4 still running... waiting ... 3 still running... waiting ... 2 still running... waiting ... 1 still running... SIGNAL HEARD! STOP RUN() still running... SIGNAL HEARD! STOPPING listen: 1 run: 1
Please excuse me if this appears to be a daft question. I am still fairly new to perl and also not well experienced when it comes to threading. Thank you!

Replies are listed 'Best First'.
Re: parallelism in threaded subroutines?
by BrowserUk (Patriarch) on Jul 24, 2015 at 22:56 UTC
    It appears to me that run() is being ran first and for a good amount of time before listen() is executed. How can I make this work?

    The problem is a simple one. As each of your subroutines is running in a tight loop, the first one you set running will have looped many times before the second one gets started a split second later.

    The fix is to slow those loops down. In the following I've added the subroutine pause() which is called from within both threads and causes them to only loop once every 1/10th of a second:

    #!/usr/bin/perl use threads; use threads::shared; sub pause { my $delay = shift; select '','','', $delay; } my ($stop) : shared; $stop = 0; my $running_t = threads->new(\&run, 2); my $listening_t = threads->new(\&listen, 1); sub listen { my $cd = 10; while ($cd > 0) { print "waiting ... $cd\n"; pause( 0.1 ); $cd--; } print "SIGNAL HEARD! STOP RUN()\n"; $stop = 1; } sub run { while(!$stop) { print "still running...\n"; pause( 0.1 ); } print "SIGNAL HEARD! STOPPING" } my @running_ret = $running_t->join; my @listening_ret = $listening_t->join; print "listen: @listening_ret\n"; print "run: @running_ret\n";

    Now the output shows that they do indeed run concurrently:

    C:\test>junk79 still running... waiting ... 10 still running... waiting ... 9 still running... waiting ... 8 still running... waiting ... 7 still running... waiting ... 6 still running... waiting ... 5 still running... waiting ... 4 still running... waiting ... 3 still running... waiting ... 2 still running... waiting ... 1 still running... SIGNAL HEARD! STOP RUN() SIGNAL HEARD! STOPPINGlisten: 1 run: 1

    Play with the pause values (0.1) and see how different values produce different effects.


    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". I knew I was on the right track :)
    In the absence of evidence, opinion is indistinguishable from prejudice.
    I'm with torvalds on this Agile (and TDD) debunked I told'em LLVM was the way to go. But did they listen!
      That makes sense, thank you!
Re: parallelism in threaded subroutines?
by Anonymous Monk on Jul 24, 2015 at 23:01 UTC

    but from the output, it does not seem like the two subroutines are truly being executed in parallel which I require. It appears to me that run() is being ran first and for a good amount of time before listen() is executed. How can I make this work?

    The output is irrelevant :)

    They are being executed in parallel

    The output might change if you do  STDOUT->blocking(0);

      or  STDOUT->autoflush(1); :)
        gotcha, thanks!