in reply to Re^10: Forking Clients
in thread Forking Clients

The point I've being trying to arrive at is that if, once you get to the point of needing the information, you have nothing else to do but wait for it to be available, then you do not need to do anything special.

The handles in this case are simply the thread handles:

my( $networkinfo ) = threads->create( sub{ $remoteServer->getNetworkInfo() } ); my( $sysLog ) = threads->create( sub{ $remoteServer->getSystemLog() } ); my( $scsiInfo ) = threads->create( sub{ $remoteServer->getScsiInfo() } ); ... anything else that needs doing ## Now you're ready for the network info my @networkinfo = $networkinfo->join; ... ## Now you're ready for the scsi info my @scsiinfo = $scsiInfo->join; ... ## Now you're ready for the syslog my @syslog = $sysLog->join;

There are 3 things to note here:

  1. Wrapping the method calls in subs on the thread create.

    As you cannot take a reference to a method, you have to wrap the method call in a sub to create a closure.

    In every other way, that method call should be exactly as it would be if no threading was involved.

  2. The scalars used to hold the thread handles returned by the threads->create() must be placed in parens if the method is to return a list.

    This is to ensure that the method is called in a list context. Whatever context threads->create() is called in when the thread is started, is the context that will be transferred to thread when it starts.

  3. The join will return the results of the method called.

    If the thread has completed when you call join, it will return teh results straight away. If it hasn't, it will block until it does.

    If you want the commands to time out after some period of time, that should be done internally to the method itself. It can then choose to either log and die, or return undef or an exception object to indicate that the command failed to complete, just as it would have to do if called synchronously.

The trick with threading, is that your code, at each level, should operate synchronously first. Then asynchronously.

Depending upon the design of your library, you might also use a thread internally to achieve the timeout, but that is a separate issue from the main code. You should not conflate that timeout mechanism, however it is achieved, with the mechanism for running the methods asynchronously.


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.
"Too many [] have been sedated by an oppressive environment of political correctness and risk aversion."

Replies are listed 'Best First'.
Re^12: Forking Clients
by gepapa (Acolyte) on Oct 16, 2008 at 17:57 UTC

    This makes sense, thank you for your clear explanation and for sticking with me through all my questions.

    I assume in the instances where I don't need the information, lets say for example I kick of some command blindly, then I can just not do a join for it. Is this correct?

    Again thank you for your help, I will play with this more today, and post back my results and questions if I have any.

      I assume in the instances where I don't need the information, lets say for example I kick of some command blindly, then I can just not do a join for it. Is this correct?

      If there is nothing useful returned or you just aren't interested in what is, just detach it at the point of creation:

      threads->create( ...)->detach;

      And any return will be discarded.

      If you're not sure if you will want the returns or not, start it in the normal way and decide later. If you want it, do the join. If you don't detach it as soon as you know that.


      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^12: Forking Clients
by Anonymous Monk on Oct 21, 2008 at 14:44 UTC

    As a followup, I have a separate issue that I think could be solved via threads as well.

    In certain instances, a system call might be made which in turn requires some user input, this system call will essentially hang there until the underlying process waiting for the response is killed. What I was hoping of doing was to create an asynchronous thread and have it run the command, I would loop for some set amount of time checking to see if the thread is joinable, if it is then great, if it times out then exit or kill the thread.

    I can't do the timeout in the function itself since there will be no response to the system call, that is why I am attempting to do it via thread that I can kill. The issue I am seeing is that after I launch the thread, anytime I attempt to do anything with the thread, i.e. to get information on it, it hangs.

    Any ideas? Thanks

    my $queue1 = new Thread::Queue; #Thread Timeout Test my $command = 'diskpart'; #my ($thr) = threads->create(sub {return `$command`;}); my ($thr) = async{ my @resp1 :shared = `$command`; $queue1->enqueue(\@resp1, undef); return; }; threads->list(); my $count = 60 * 1; #wait a min (testing) while ($count and !$thr->is_joinable()) { sleep(1); count--; } if (!$thr->is_joinable()) { threads->exit(); } ...

    The threads->list() call hangs (so does any other thread related call. If I do $command = 'dir'; everything works as expected since it is not stuck waiting for user input.