Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Perl multithreading and foreach

I am writing a simple Perl script that should run other Perl scripts simultaneously. I don't know how to make the main program wait for running threads. Sleep IS NOT a suitable solution because of many reason. This is my "main" script:

#!/usr/bin/perl
use threads;
main:
{
    if ($#ARGV == -1) { usage(); exit(1); }
    my $hostname = $ARGV[0];
    my $thrssh = threads ->create(\&ssh, $hostname);
    my $thrdns = threads ->create(\&dns, $hostname);
    my $thrping = threads ->create(\&ping, $hostname);
    my $thrsmtp = threads ->create(\&smtp, $hostname);
    my $thrproxy = threads ->create(\&proxy, $hostname);
}
sub ssh {
    threads->detach();
    my $hostname = @_;
    #print "SSH\n";
    #LAUNCH SSH SCRIPT
}
#OTHER SUBROUTINES...
sub proxy {
    threads->detach();
    my $hostname = @_;
    #print "PROXY\n";
    #LAUNCH PROXY SCRIPT
}

If I try to run this script the first thing I can notice is that prints are "sequential", I thought text was messed up but maybe Print is exclusive I don't know. Main problem is that the last two subroutines don't have time to be executed.

SSH
DNS
PING
Perl exited with active threads:
2 running and unjoined
0 finished and unjoined
0 running and detached

If I use join instead of detach the subroutines become "sequential", for example if I put a sleep in sub ssh other threads will wait before starting. I want them to be parallel and the main program to close ONLY when all threads are finished, any help?

I actually have another question, if I have to run multiple threads in a foreach cicle when I am supposed to join them? ie:

my $thrssh;
foreach $mynode ($nodeset->get_nodelist) {
    #...
    $thrssh = threads ->create(\&ssh, $port, $hostname);
    #...
}
$thssh->join();

Is that right?

like image 420
raz3r Avatar asked Nov 14 '11 09:11

raz3r


1 Answers

You need to join all your threads from the main thread after they have all been started. Don't detatch if you don't want the interpreter to exit while the threads are still running.

...
my $thrssh = threads ->create(\&ssh, $hostname);
my $thrdns = threads ->create(\&dns, $hostname);
...
$thrssh->join();
$thrdns->join();
...

Regarding your edit: no, it's not right. You need to keep a reference to each thread you create, otherwise you can't join them.

Do something like:

my @thrs;
foreach $mynode ($nodeset->get_nodelist) {
    #...
    $thrssh = threads ->create(\&ssh, $port, $hostname);
    push @thrs, $thrssh;
    #...
}
$_->join() for @thrs;
like image 64
Mat Avatar answered Nov 20 '22 12:11

Mat