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

The main program is essentially a test script, which communicates via rpc with another server which will execute system commands. There are a bunch of intermediary modules between the main test script and the actual point where the rpc call is made. This is pretty much why I am trying to dumb it down so I understand the basics.

Here is what I want to do in the main program

my $remoteServer = new Host($ip); ... #I want the following to run concurrently my @networkinfo = $remoteServer->getNetworkInfo(); my @sysLog = $remoteServer->getSystemLog(); my @scsiInfo = $remoteServer->getScsiInfo(); #So I have kicked all these off, I need to get the #networkinfo and scsiInfo information back before #continuing. The sy +sLog I don't need, its going to be #grabbed way down the line, possibly at the end of the #program ... package Host; sub getNetworkInfo { ($self) = @_; my @results = $self->rpc('RPCService::system_call', 'ipconfig /all' +); return @results; } sub getScsiInfo { ($self) = @_; my @results = $self->rpc('RPCService::system_call', 'scsinit -a'); return @results; } sub getSystemLog { ($self) = @_; my @results = $self->rpc('RPCService::system_call', 'eventlog -a'); return @results; } sub rpc { ($self, $func, $command) = @_; my $ip = $self->getIP(); #start threaded/process code here ..??.. my $port = $self->getPort(); my $connection = ClarRPC->connect($ip, $port); my @resp = $connection->rpc($func, $command); $connection->disconnect(); ..??.. #end threaded/process code here }

Let me know if I need to clear anything up. Thanks!

Replies are listed 'Best First'.
Re^9: Forking Clients
by BrowserUk (Patriarch) on Oct 16, 2008 at 13:59 UTC

    You keep skipping over the important part--the bit above that is just comments--so I'll ask a very specific question.

    You've started all your remote commands--they're running asynchronously. You've done anything else you might want to do before you need the results of the first one--say the getNetworkInfo() in your example--and you are now ready for those results. When you started that command, you got back a handle as I suggested above, and you test the handle to see if the results are ready. What do you do if not?

    What are you going to do in the else clause below?

    my $networkinfo = $remoteServer->getNetworkInfo(); my $sysLog = $remoteServer->getSystemLog(); my $scsiInfo = $remoteServer->getScsiInfo(); ... anything else that needs doing ## Now you're ready for the network info my @networkinfo; if( $networkinfo ) { @networkinfo = $networkinfo->(); } else { ## What would you do here? }

    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.

      If I was at the point where I needed the information, I would wait for some specified amount of time. If it timesout I would kill the process and most likely die.

      Could you expand upon the use of the handles, I can't say I have ever used this way of doing things. Thanks.

        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.