http://www.perlmonks.org?node_id=1021943

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

Hello Everyone

I ran across a problem and am pondering the best way to implement it. I have some working code but am not sure my path is a good one. I will put enough code here so that people can comment. If any of you have good reference material on program design around threads and PERL please post. I have done a chunk of work with threads but I can't say that I cared too much about synchronizing the output they produce.

The problem is that of not orchestrating a bunch of threads with a lot of code yet needing some synchronization. My problem is I need to get command output from several thousand network devices all of which are sitting behind a proxy. The basic program is take in a file of machines and a file of commands, run the commands and drop the responses into files.

The problem I am trying to solve is the printed order of the commands in the output file. I would like the command output to be in the order that is in the file. After a lot of tinkering and debugging of different ideas, I settled on creating a shared array that holds the order of thread creation. After the threads are populated with the information to print, I allow them to print in the order of their creation. It isn't very elegant and I am guessing there is a better way. It just hasn't hit me yet. So my question is what is a good way to handle the file creation with multiple threads spitting out files at the same time. I have seen some information out there about sharing filehandles between threads and the like but nothing about a good design to deal with something like this. Frankly, another design might be to have the threads print to separate files and the synch problem goes away. Not really what I wanted though.

use threads; use threads::shared; my $semaphore = new Thread::Semaphore; my $live_threads :shared = 0; my $thrwait_to_finish :shared = 5; my $maximum_active_threads :shared = 10; my @tid_array :shared; my @commands = ("show ip interface brief | exclude unassigned", "show vlan", "show vrf"); my @machines = ('1.1.1.1', '2.2.2.2', '3.3.3.3'); foreach my $cmd (@commands) { foreach my $machine_name (@machines) { my $url = "http://proxy:port/api/device/$machine_name/execute?cmd= +$cmd"; if ($live_threads >= $maximum_active_threads) { my $new_thread_num = wait_for_finish(); $semaphore->down(); $live_threads = $new_thread_num; $semaphore->up(); } else { my $thread = threads->create('get_request', $cmd, $url, $machi +ne_name); my $tid = $thread->tid(); $semaphore->down(); push (@tid_array, $tid); $live_threads++; $semaphore->up(); } } } sub get_request { sleep 1; my $cmd = $_[0]; my $url = $_[1]; my $machine_name = $_[2]; my $thread_id = threads->tid(); my $count = '0'; ... $web_response = $response->content; ... while ($thread_id != $tid_array[0]) { print "Thread_sleaping: $thread_id\n"; sleep 1; } ... $semaphore->down(); shift @tid_array; $semaphore->up(); print $fh ($webresponse); }