2010-10-30 5 views
4

J'ai ce simple démon perl:Est-ce que le sommeil est interrompu quand un signal est reçu en perl?

#!/usr/bin/perl 

use strict; 
use warnings; 
use Proc::Daemon; 

Proc::Daemon::Init; 

my $continue = 1; 

$SIG{TERM} = sub { $continue = 0 }; 
$SIG{USR1} = sub { do_process(1) }; 

# basic daemon                      

boxesd_log("started boxesd"); 

while ($continue) { 
    do_process(0); 
    sleep(30); 
} 

boxesd_log("finished boxesd"); 

exit(0); 

# required subroutines                    

sub do_process { 
    my ($notified) = @_; 
    boxesd_log("doing it $notified"); 
} 

Mais il y a quelque chose qui ne fonctionne pas correctement.

Lorsque le démon démarre, il enregistre toutes les 30 secondes sans notification comme prévu:

Sat Oct 30 21:05:47 2010 doing it 0 
Sat Oct 30 21:06:17 2010 doing it 0 
Sat Oct 30 21:06:47 2010 doing it 0

Le problème vient quand j'envoie le signal USR1 au processus en utilisant kill -USR1 xxxxx. La sortie est pas ce que je pense:

Sat Oct 30 21:08:25 2010 doing it 1 
Sat Oct 30 21:08:25 2010 doing it 0

je reçois deux entrées consécutives, l'une de la sous-routine de traitement du signal et une autre forme la boucle toujours en cours d'exécution. Il semble que le sommeil soit interrompu à chaque fois que le signal USR1 est reçu.

Que se passe-t-il?

Répondre

8

Le sommeil est interrompu dans le sens où votre programme traitera le signal entrant, mais la boucle continuera (se remettra en veille) jusqu'à la réception d'un signal TERM. Ce comportement est documenté pour la fonction sleep():

Peut être interrompu si le processus reçoit un signal tel que "SIGALRM".

Notez que si vous avez besoin de dormir pendant 30 secondes, même si interrompu par un signal, vous pouvez déterminer le nombre de secondes dormi puis dormir à nouveau pour le reste:

while (1) 
{ 
    my $actual = sleep(30); 
    sleep(30 - $actual) if $actual < 30; 
} 

PS. Vous pouvez en savoir plus sur la gestion des signaux dans perldoc perlipc et dans pratiquement tous les manuels de programmation Unix par W. Richard Stevens. :)

+3

Vous n'êtes pas en train de vérifier si votre deuxième 'sleep' a été interrompu aussi. Pour le gérer correctement, vous avez besoin d'une boucle de quelque sorte, pas seulement un 'if'. – cjm

+0

Er, la réponse éditée est une boucle infinie. :( – mark4o

+0

@ mark4o: infini jusqu'à ce qu'un signal l'interrompt, oui, ce qui est généralement ce que font les démons. (J'ai enlevé la variable '$ continue' pour plus de clarté, car elle ne correspondait pas à la question centrale de comment' sleep' se comporte Il est évident que l'on pourrait vouloir rendre le code plus compliqué, par exemple dormir à nouveau sur une seconde interruption comme cjm mentionné.) – Ether

Questions connexes