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

Hi, is it possible to pass a reference to a subroutine to a thread? What I want to do is to give a worker thread a list of subroutines that it should call but this fails. I did not find a kind of 'shared' attribute for subroutines like it is present for scalar/array/hash references. Here is some code that illustrates my problem:
use strict; use warnings; use threads; use threads::shared; use Thread::Queue; my $queue = new Thread::Queue; sub hello { print "Hello\n"; } sub worker { my $tid = threads->self->tid; print "[$tid] Starting\n"; while (my $job = $queue->dequeue) { print "Got a job\n"; } print "[$tid] Terminating\n"; } my @tlist; my $workers = 4; # Start Workers for (my $i = 0; $i < $workers; $i++) { push(@tlist, threads->new(\&worker)); } for (my $i = 0; $i < 10; $i++) { $queue->enqueue(\&hello); # This causes my trouble } sleep(5); # Wait for workers to finish foreach my $w (@tlist) { $queue->enqueue(undef); } foreach my $w (@tlist) { $w->join; }
Does anybody now how I can call the subs that I pass to a thread? Thanks for your help! Kind regards, Stephan

Replies are listed 'Best First'.
Re: Threaded Perl: References to subroutines to threads
by liverpole (Monsignor) on Oct 09, 2007 at 14:19 UTC
    Hi stephan_a,

    My advice would be to use a dispatch table, and just pass the key which corresponds to the subroutine you wish to invoke.

    For example:

    use strict; use warnings; use threads; use threads::shared; use Thread::Queue; my $queue = new Thread::Queue; my $pdispatch = { 'greeting' => \&hello, }; sub hello { print "Hello\n"; } sub worker { my $tid = threads->self->tid; print "[$tid] Starting\n"; while (my $job = $queue->dequeue) { print "Got a job: '$job'\n"; my $psub = $pdispatch->{$job}; if ($psub || 0) { $psub->(); } } print "[$tid] Terminating\n"; } my @tlist; my $workers = 4; # Start Workers for (my $i = 0; $i < $workers; $i++) { push(@tlist, threads->new(\&worker)); } for (my $i = 0; $i < 10; $i++) { $queue->enqueue('greeting'); # No more trouble :-) } sleep(5); # Wait for workers to finish foreach my $w (@tlist) { $queue->enqueue(undef); } foreach my $w (@tlist) { $w->join; }

    s''(q.S:$/9=(T1';s;(..)(..);$..=substr+crypt($1,$2),2,3;eg;print$..$/
Re: Threaded Perl: References to subroutines to threads
by renodino (Curate) on Oct 09, 2007 at 15:21 UTC
    Does anybody now how I can call the subs that I pass to a thread?

    Short answer: You can't.

    Long answer: Thread::Queue is really nothing more than a threads::shared array. Which means any ref assigned to it must also be threads::shared. Since you're passing a coderef, it must be threads::shared...except threads::shared cannot be applied to coderefs.

    See liverpole's response (Re: Threaded Perl: References to subroutines to threads) for an alternative.


    Perl Contrarian & SQL fanboy

      Hi liverpole, renodino,

      thanks for you answers. I have already supposed that there are no shared coderefs so I will try the dispatcher way.

      Thanks for your help!

      Kind regards, Stephan

Re: Threaded Perl: References to subroutines to threads
by BrowserUk (Patriarch) on Oct 09, 2007 at 23:16 UTC

    This is possible, although is uses some dubious quirks of Perl to do it.

    use threads;; use Thread::Queue;; ## define a sub that prints out the thread and package it is running u +nder sub test{ print threads->self->tid, __PACKAGE__ . "::test" for 1 .. 5; };; ## test it test();; 0 main::test 0 main::test 0 main::test 0 main::test 0 main::test ## A queue for communication $Q = new Threads::Queue;; ## A thread that pulls the code ref of the queue and invokes it sub thread{ my $Q = shift; my $code = $Q->dequeue; &{ $code }->() };; ## create the thread $t = threads->create( \&thread, $Q );; ## And post the name of the code to be invoked $Q->enqueue( 'test' );; 1 main::test 1 main::test 1 main::test 1 main::test 1 main::test

    What if anything you choose to do with this information is at your own risk :)


    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.