Okay. In order to avoid spawning a new thread for each work item, it is necessary to make each worker thread loop processing new work items. Usually, I write the worker thread subroutine to do this, but I leaning towards using a generic wrapper for a one-shot processing sub.
In this way, the processing sub can be developed in a single threaded program, without consideration to the needs of multi-threading. So long as it uses all local lexical variables.
Once perfected, it can then be called from a generic worker thread wrapper that takes care of the business of processing the input and output queues, and other threading related infrastructure.
I don't thin this is prefect yet by any means. There may be a race condition in here still... I don't have a load of machines I can telnet to to try it out, so it is untested beyond a clean compile.
I'd welcome your feed back.(It looks complicated, but 60% of this is overly verbose comment. Most of which you can ditch once you've read it and replace with whatever makes sense to you.)
#! perl -slw use strict; use threads; use Thread::Queue; ## Used to pass work items to the threads my $Qin = new Thread::Queue; ## Used to retrieve results from the threads my $Qout = new Thread::Queue; ## Used to allow the main thread to know when all the ## threads have finished. my $running : shared = 0; ## Used to wrap the one-shot work item processing sub ## with a loop that will continue to process new items ## until Qin is empty sub thread { ## Get the passed parameter(s) my $command = @_; ## count 'em out $running++; ## Wait until there is some work to do sleep 1 until $Qin->pending; ## While there is work to do while( $Qin->pending ) { ## dequeue a work item and call the work sub ## with the work item and the passed parameter my $rv = telnet2Cli( $Qin->dequeue, $command ); ## return the results to the main thread ## via the Qout. $Qout->enqueue( $rv ); } ## count 'em back $running--; } ## Start the pool of workers ## passing the static command ## detached so that it cleans itself up. my @pool = map{ threads->new( \&thread, 'show version')->detach } 1 .. 5; ## Get work items from somewhere my @values; ## = getValues(...); ## Queue the work items via Qin $Qin->enqueue( @values ); ## Wait for the workers to complete sleep 1 while $running; ## retrieve the results from Qout my @versionOuput = $Qout->dequeue; ## Do something with the results. exit; ## sub callable for single threaded use. ## This sub processes a single work item. ## Wrapping it in the thread() sub allows it ## to process as many work items as are required sub telnet2Cli { require Net::Telnet::Cisco; my( $Server, $cmd ) = @_; my @output; my $session = Net::Telnet::Cisco->new( Host => $Server, input_log => "input.log.$Server" ); $session->login(Password => 'Password here'); if ($session->enable("Password here")) { $session->cmd("terminal length 0"); @output = $session->cmd($cmd); print "Output about return @output\n"; } else { warn "Cant enable: " . $session->errmsg; } $session->close; return "@output"; }
I'd also recommend that you read the Thread::Queue docs carefully, and wriet a couple of play scripts using them to get used to how they operate.
In reply to Re^11: Thread::Pool and Template Toolkit
by BrowserUk
in thread Thread::Pool and Template Toolkit
by perldragon80
| For: | Use: | ||
| & | & | ||
| < | < | ||
| > | > | ||
| [ | [ | ||
| ] | ] |