#!/usr/bin/perl
#
# Ce programme est un exemple d'utilisation de fork() en perl
#
# On sort le texte à l'écran dès qu'il est pret
$| = 1;
use strict;
use warnings;
# Attente de fork() sans attente (WNOHANG)
use POSIX ":sys_wait_h" ;
# Tableau de données à traiter
my @array = qw(rt_01 rt_02 lb_01 lb_02 lb_03 sw_01 sw_02 sw_03 rt_03 rt_04 rt_05 rt_06 rt_07 fw_01 fw_02);
# Nombre de traitements simultanés maximum:
my $taches_max = 4;
# Un tableau de hashage permettant de controller l'affichage de messages ...
my %debug = (
'child_fork' => 0, # ... à la création d'un fils par le père
'child_inner' => 0, # ... pendant le traitement d'un fils
'child_exit' => 0, # ... lorsque le fils va traiter
'queue' => 1, # ... quand on change l'etat de la queue
) ;
########################################################################
# Variables internes
my %taches ; # Hash contenant les PID des fils
my $taches_size = 0 ; # Nombre d'éléments dans le hash
my $left = @array ; # Elements restant à traiter
sub show_taches() {
return unless $debug{'queue'};
printf "Etat de la queue : [%s/%s]", $taches_size, $taches_max ;
if( ($left - $taches_size) ) {
printf ", %s tâches en attente", ($left - $taches_size);
}
print "\n";
}
print "Début du traitement de $left tâches\n";
show_taches();
# Boucle sur tout les équipements
foreach my $equipement (@array) {
my $pid = fork ;
# Si on a un pid c'est celui du fiston qui a été spawné
if ($pid) {
print "$$> child forké avec le pid $pid.\n" if $debug{'child_fork'};
# On enregistre le pid du fils
$taches{$pid} = 1;
$taches_size++;
show_taches();
# Si le pid renvoyé est 0 on est dans le process forké
} elsif ($pid == 0) {
# fils
my $sleep_for = 1 + int rand(5) ;
print "$$> $equipement fait une sieste de $sleep_for seconds.\n" if $debug{'child_inner'};
sleep $sleep_for ;
print "$$> Réveil de $equipement après $sleep_for s.).\n" if $debug{'child_exit'};
exit(0);
# Sinon (valeur négative) il y a eu une erreur
} else { die "Erreur de fork : $!\n"; }
# On attend jusqu'à ce qu'une tâche se finisse ou que l'on puisse encore en lancer
my $child_pid ;
do {
# waitpid -1 attend un changement de statut de n'importe quel fils
# renvoi le pid d'un child qui a bougé ou 0 si rien n'a changé
$child_pid = waitpid( -1, WNOHANG );
# Le child est sorti, on le retire des tâches en cours
if( $child_pid > 0 ) {
delete $taches{$child_pid};
$taches_size-- ;
$left--;
show_taches();
}
} until(
( ($child_pid > 0) or ($taches_size < $taches_max) ) and ( ($left == 0) or ( $taches_size < $left ) ) ); } print "Fin du traitement\n";
La sortie du programme est ci-dessous. Malheureusement il est difficile de représenter les temps d'attente. C'est peut-être une idée d'amélioration.
Début du traitement de 15 tâches
Etat de la queue : [0/4], 15 tâches en attente
Etat de la queue : [1/4], 14 tâches en attente
Etat de la queue : [2/4], 13 tâches en attente
Etat de la queue : [3/4], 12 tâches en attente
Etat de la queue : [4/4], 11 tâches en attente
Etat de la queue : [3/4], 11 tâches en attente
Etat de la queue : [4/4], 10 tâches en attente
Etat de la queue : [3/4], 10 tâches en attente
Etat de la queue : [4/4], 9 tâches en attente
Etat de la queue : [3/4], 9 tâches en attente
Etat de la queue : [4/4], 8 tâches en attente
Etat de la queue : [3/4], 8 tâches en attente
Etat de la queue : [4/4], 7 tâches en attente
Etat de la queue : [3/4], 7 tâches en attente
Etat de la queue : [4/4], 6 tâches en attente
Etat de la queue : [3/4], 6 tâches en attente
Etat de la queue : [4/4], 5 tâches en attente
Etat de la queue : [3/4], 5 tâches en attente
Etat de la queue : [4/4], 4 tâches en attente
Etat de la queue : [3/4], 4 tâches en attente
Etat de la queue : [4/4], 3 tâches en attente
Etat de la queue : [3/4], 3 tâches en attente
Etat de la queue : [4/4], 2 tâches en attente
Etat de la queue : [3/4], 2 tâches en attente
Etat de la queue : [4/4], 1 tâches en attente
Etat de la queue : [3/4], 1 tâches en attente
Etat de la queue : [4/4]
Etat de la queue : [3/4]
Etat de la queue : [2/4]
Etat de la queue : [1/4]
Etat de la queue : [0/4]
Fin du traitement
Aucun commentaire:
Enregistrer un commentaire