Einfache Signale – C-Programmierung und Alarmfunktion

Lesezeit: 3 Minuten
#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");
}

Ich erwarte, dass das Programm nach 2 Sekunden “Hallo” ausgibt, aber stattdessen lautet die Ausgabe “zsh: alarm ./a.out”.

Irgendeine Ahnung, was los ist?

Sie haben vergessen, den Alarm-Handler anfangs festzulegen. Ändern Sie den Anfang von main() wie:

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

Außerdem wird der Signalhandler wahrscheinlich nichts drucken. Das liegt daran, dass die C-Bibliothek die Ausgabe zwischenspeichert, bis sie ein Zeilenende sieht. So:

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

Für ein reales Programm ist das Drucken von einem Signalhandler nicht sehr sicher. Ein Signalhandler sollte so wenig wie möglich tun, vorzugsweise nur hier oder da ein Flag setzen. Und die Flagge sollte deklariert werden volatile.

  • Beispiel aus der Praxis: Ich habe einmal an einem System gearbeitet, das eine Access-Datenbank als Backend verwendet hat, und unter bestimmten Umständen a printf() Der Aufruf eines Signal-Handlers würde in die .mdb-Datei statt in stdout schreiben, wodurch die Datenbank irreparabel wird.

    – Johannes Bode

    23. November 2009 um 20:22 Uhr

Benutzer-Avatar
McPherrinM

Sie setzen den Handler nicht in Ihrem main Funktion.

Bevor Sie es tun alarm(2)lege das signal(SIGALRM, ALARMhandler); in deiner main.

Da sollte es funktionieren.

Beachten Sie, dass Ihr “All Done” niemals gedruckt wird, da Sie in der While(1)-Schleife bleiben, nachdem der Signalprozessor ausgeführt wurde. Wenn Sie möchten, dass die Schleife unterbrochen wird, benötigen Sie ein Flag, das der Signalhandler ändert.

#include <stdio.h>
#include <signal.h>
#include <unistd.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;
}

  • +1 Für das schöne Programm. Ich denke, du müsstest anrufen alarm(2) im Signalhandler: normalerweise eins alarm() Anruf erzeugt nur eine einzige SIGALRM

    – Andomar

    23. November 2009 um 16:24 Uhr

  • Natürlich haben Sie Recht. Ich habe diesen Code offensichtlich nicht getestet und seit einiger Zeit keine Signale mehr auf diese Weise verwendet (insbesondere sind sie in einer Thread-Umgebung nutzlos, um sie auf diese Weise zu verwenden).

    – McPherrinM

    24. November 2009 um 5:29 Uhr

  • Was ist die Notwendigkeit, flüchtige Speicherklassen für Breakflag-Variablen anzugeben?

    – Sujin

    11. Juni 2013 um 13:50 Uhr

  • Die Volatilität sollte den Compiler daran hindern, Speicher oder Ladevorgänge zu optimieren, sodass die beiden verschiedenen Teile der Codeausführung (Hauptschleife, Signalhandler) die Werte des anderen Teils immer korrekt sehen. Ich bin jedoch nicht von der Korrektheit dieses Codes überzeugt und würde stattdessen vielleicht einen atomaren verwenden.

    – McPherrinM

    11. Juni 2013 um 19:14 Uhr

  • Hinzufügen #include <unistd.h> um die Warnmeldung der impliziten Deklaration der Funktionen ‘alarm’ und ‘sleep’ zu beseitigen

    – charles.cc.hsu

    25. März 2017 um 3:42 Uhr

Sie installieren den Signalhandler nicht zuerst.
Sie müssen dem System mitteilen, dass Sie das Signal verarbeiten möchten, bevor Sie es tatsächlich empfangen, also müssen Sie anrufen signal() von der Hauptleitung, bevor das Signal kommt.

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

Andomar hat Recht. Ich teste dies und Version 1 druckt (jede Sekunde):

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

Version 2 druckt (alle fünf Sekunden):

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

Der Code lautet also:

#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);
}

1364850cookie-checkEinfache Signale – C-Programmierung und Alarmfunktion

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy