1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90
| #!/usr/bin/perl
use strict;
use warnings;
use Data::Dumper;
use threads;
use threads::shared;
use Thread::Semaphore;
my @list = ("command1", "command2", "command3", "command4", "command5", "command6", "command7", "command8", "command9", "command10");
my $nombre_de_jobs_en_parallele = 4;
# le sémaphore permet de réguler le nombre de jobs en simultané, bloquant le processus principal tant qu'il n'y a pas de place de libre
my $semaphore = Thread::Semaphore->new($nombre_de_jobs_en_parallele);
# quelques variables partagées
my $cpt:shared;
my $failed:shared;
$cpt = 0;
$failed = 0;
my $started = 0;
# le point d'entrée du job en parallèle
sub forked_job($$$$$){
my $command = shift;
my $index = shift;
my $cpt_ref = shift;
my $failed_ref = shift;
my $sema_ref = shift;
# simule un travail de durée indéterminée entre 0 et 10 sec
my $int = int 10 * rand();
print "Le job $index va dormir $int sec au lieu d'exécuter la commande $command\n";
sleep($int);
# simule une erreur
my $str = "";
if ($int == 4){
$str = " avec une erreur";
$$failed_ref++;
}
print "Le job $index vient de se terminer$str\n";
# incrémente le nombre de jobs finis
$$cpt_ref++;
# on a une place de libre. Ne pas oublier de libérer le sémaphore même en cas d'erreur
$$sema_ref->up();
return;
}
# démarre tous les jobs, sauf erreur
while ($started < scalar @list && !$failed){
my $command = $list[$started];
# incrémente le compteur
$started++;
# avons nous une place de libre ?
$semaphore->down();
# si le sémaphore est a 0, le processus principal va se bloquer en attendant une nouvelle place
print "Creation du job $started\n";
my $thr = threads->create("forked_job", (
$command,
$started,
\$cpt,
\$failed,
\$semaphore
)
);
# détache le job du thread principal, rend la main au thread principal
$thr->detach();
# si on veut attendre la fin du job pour redonner la main, on utilise
# $thr->join();
}
# attend les derniers jobs
while ($cpt < $started){
print "Seul $cpt jobs finis sur $started, sleeping\n";
sleep(3);
}
print "$cpt jobs lances, $failed échoués, sur les ".scalar @list." prévus\n";
print "The End.\n"; |
Partager