web-dev-qa-db-fra.com

Signaux simples - Programmation C et fonction d'alarme

#include  <stdio.h>
#include  <signal.h>


void  ALARMhandler(int sig)
{
  signal(SIGALRM, SIG_IGN);          /* ignore this signal       */
  printf("Hello");
  signal(SIGALRM, ALARMhandler);     /* reinstall the handler    */
}

int main(int argc, char *argv[])
{
  alarm(2);                     /* set alarm clock          */
  while (1)
    ;
  printf("All done");
}

Je m'attends à ce que le programme imprime "bonjour" après 2 secondes, mais à la place, la sortie est "zsh: alarm ./a.out"

Une idée de ce qui se passe?

24
qwer

Vous oubliez de définir le gestionnaire d'alarmes au départ. Modifiez le début de main() comme:

int main(int argc, char *argv[])
{
   signal(SIGALRM, ALARMhandler);
   ...

De plus, le gestionnaire de signal n'imprimera probablement rien. C'est parce que la bibliothèque C met en cache la sortie jusqu'à ce qu'elle voit une fin de ligne. Donc:

void  ALARMhandler(int sig)
{
  signal(SIGALRM, SIG_IGN);          /* ignore this signal       */
  printf("Hello\n");
  signal(SIGALRM, ALARMhandler);     /* reinstall the handler    */
}

Pour un programme réel, l'impression à partir d'un gestionnaire de signaux n'est pas très sûre. Un gestionnaire de signal doit faire aussi peu que possible, de préférence en ne plaçant un drapeau qu'ici ou là. Et le drapeau doit être déclaré volatile.

33
Andomar

Vous ne définissez pas le gestionnaire dans votre fonction main.

Avant de faire alarm(2), placez signal(SIGALRM, ALARMhandler); dans votre main.

Cela devrait fonctionner alors.

Notez que votre "All Done" ne sera jamais imprimé, car vous resterez dans la boucle while (1) après l'exécution du processeur de signal. Si vous voulez que la boucle soit rompue, vous aurez besoin d'un indicateur que le gestionnaire de signaux change.

#include <stdio.h>
#include <signal.h>

/* number of times the handle will run: */
volatile int breakflag = 3;

void handle(int sig) {
    printf("Hello\n");
    --breakflag;
    alarm(1);
}

int main() {
    signal(SIGALRM, handle);
    alarm(1);
    while(breakflag) { sleep(1); }
    printf("done\n");
    return 0;
}
9
McPherrinM

Vous n'installez pas le gestionnaire de signaux en premier.
Vous devez indiquer au système que vous souhaitez gérer le signal avant de le recevoir, vous devez donc appeler signal() depuis le réseau principal avant que le signal ne vienne.

int main(int argc, char *argv[])
{
  signal(SIGALRM, ALARMhandler);     /* install the handler    */
  alarm(2);                     /* set alarm clock          */
  while (1);
}
5
Arkaitz Jimenez

Andomar a raison. Je teste cela et la version 1 s'imprime (toutes les secondes):

Hi...
Hi...
Hi...
Hi...
BYE
Hi...
...

version 2 imprime (toutes les cinq secondes):

Hi...Hi...Hi...Hi...BYE
Hi...Hi...Hi...Hi...BYE
...

Le code est donc:

#include <stdio.h>
#include <unistd.h>
#include <signal.h>

# define T 5

int flag = T;

void sigalrm_handler(int);

int  main(void)
{
    signal(SIGALRM, sigalrm_handler);   
    alarm(1);                         
    while (1);  
}

void sigalrm_handler(int sig)
{
    if(--flag){
        printf("Hi...\n");   /*version 1*/
        /*printf("Hi...");*/ /*version 2*/
    }else{
        printf("BYE\n");
        flag=T;     
    }
    alarm(1);
}
4
alemol