Suche…


Syntax

  • void (* signal (int sig, void (* func) (int))) (int);

Parameter

Parameter Einzelheiten
sig Das Signal, das den Signal-Handler auf " SIGABRT , " SIGFPE , " SIGILL , " SIGTERM , " SIGINT , " SIGSEGV oder einen durch die Implementierung definierten Wert setzen soll
func Der Signalhandler, einer der folgenden: SIG_DFL für den Standardhandler, SIG_IGN zum Ignorieren des Signals oder ein Funktionszeiger mit der Signatur void foo(int sig); .

Bemerkungen

Die Verwendung von Signalhandlern mit nur den Garantien des C-Standards unterliegt verschiedenen Einschränkungen, was im benutzerdefinierten Signalhandler möglich oder nicht möglich ist.

  • Wenn die benutzerdefinierte Funktion während der Behandlung von SIGSEGV , SIGFPE , SIGILL oder einem anderen implementierungsdefinierten Hardware-Interrupt zurückkehrt, ist das Verhalten durch den C-Standard nicht definiert. Dies liegt daran, dass die Schnittstelle von C keine Mittel zur Änderung des fehlerhaften Zustands gibt (z. B. nach einer Division durch 0 ) und daher bei der Rückkehr des Programms genau der gleiche fehlerhafte Zustand ist wie vor dem Auftreten des Hardware-Interrupts.

  • Wenn die benutzerdefinierte Funktion als Ergebnis eines abort oder raise aufgerufen wurde raise darf der Signalhandler nicht erneut raise aufrufen.

  • Signale können während jeder Operation eintreffen, und daher kann die Unteilbarkeit der Operationen im Allgemeinen nicht garantiert werden, und die Signalverarbeitung funktioniert bei der Optimierung nicht gut. Daher müssen alle Änderungen an den Daten in einem Signalhandler an Variablen vorgenommen werden

    • vom Typ sig_atomic_t (alle Versionen) oder einem sig_atomic_t atomaren Typ (seit C11, optional)
    • das sind volatile qualifiziert.
  • Bei anderen Funktionen der C-Standardbibliothek werden diese Einschränkungen normalerweise nicht beachtet, da sie möglicherweise Variablen im globalen Status des Programms ändern. Der C-Standard gibt nur Garantien für abort , _Exit (seit C99), quick_exit (seit C11), signal (für dieselbe Signalnummer) und einige atomare Operationen (seit C11).

Das Verhalten ist vom C-Standard nicht definiert, wenn eine der oben genannten Regeln verletzt wird. Plattformen können über bestimmte Erweiterungen verfügen, diese sind jedoch im Allgemeinen über diese Plattform nicht portierbar.

  • Normalerweise haben Systeme eine eigene Liste von Funktionen, die asynchrones Signalsicher sind , d. H. Von C-Bibliotheksfunktionen, die von einem Signalhandler verwendet werden können. ZB ist oft printf eine dieser Funktionen.

  • Insbesondere definiert der C-Standard nicht viel über die Interaktion mit seiner Thread-Schnittstelle (seit C11) oder mit plattformspezifischen Thread-Bibliotheken wie POSIX-Threads. Solche Plattformen müssen die Interaktion solcher Thread-Bibliotheken mit eigenen Signalen festlegen.

Signalbehandlung mit "Signal ()"

Signalnummern können synchron sein (wie SIGSEGV - Segmentierungsfehler), wenn sie durch eine Fehlfunktion des Programms selbst ausgelöst werden, oder asynchron (wie SIGINT - interaktive Aufmerksamkeit), wenn sie von außerhalb des Programms initiiert werden, z. B. durch Tastendruck als Cntrl-C .

Die Funktion signal() ist Teil des ISO-C-Standards und kann verwendet werden, um eine Funktion für die Verarbeitung eines bestimmten Signals zuzuweisen

#include <stdio.h>  /* printf() */
#include <stdlib.h> /* abort()  */
#include <signal.h> /* signal() */

void handler_nonportable(int sig)
{
    /* undefined behavior, maybe fine on specific platform */
    printf("Catched: %d\n", sig);
    
    /* abort is safe to call */
    abort();
}

sig_atomic_t volatile finished = 0;

void handler(int sig)
{
    switch (sig) {
    /* hardware interrupts should not return */
    case SIGSEGV:
    case SIGFPE:
    case SIGILL:
C11
      /* quick_exit is safe to call */
      quick_exit(EXIT_FAILURE);
C11
      /* use _Exit in pre-C11 */
      _Exit(EXIT_FAILURE);
    default:
       /* Reset the signal to the default handler, 
          so we will not be called again if things go
          wrong on return. */
      signal(sig, SIG_DFL);
      /* let everybody know that we are finished */
      finished = sig;
      return;
   }
}

int main(void)
{

    /* Catch the SIGSEGV signal, raised on segmentation faults (i.e NULL ptr access */
    if (signal(SIGSEGV, &handler) == SIG_ERR) {
        perror("could not establish handler for SIGSEGV");
        return EXIT_FAILURE;
    }

    /* Catch the SIGTERM signal, termination request */
    if (signal(SIGTERM, &handler) == SIG_ERR) {
        perror("could not establish handler for SIGTERM");
        return EXIT_FAILURE;
    }

    /* Ignore the SIGINT signal, by setting the handler to `SIG_IGN`. */
    signal(SIGINT, SIG_IGN);


    /* Do something that takes some time here, and leaves
       the time to terminate the program from the keyboard. */

    /* Then: */

    if (finished) {
       fprintf(stderr, "we have been terminated by signal %d\n", (int)finished);
        return EXIT_FAILURE;
    }


    /* Try to force a segmentation fault, and raise a SIGSEGV */
    {
      char* ptr = 0;
      *ptr = 0;
    }

    /* This should never be executed */
    return EXIT_SUCCESS;
}

Die Verwendung von signal() wichtige Einschränkungen, was Sie in den Signalhandlern tun dürfen. Weitere Informationen finden Sie in den Anmerkungen.

POSIX empfiehlt die Verwendung von sigaction() anstelle von signal() , da dessen Verhalten nicht genau angegeben ist und die Implementierung stark variiert. POSIX definiert auch viel mehr Signale als den ISO-C-Standard, einschließlich SIGUSR1 und SIGUSR2 , die vom Programmierer für beliebige Zwecke frei verwendet werden können.



Modified text is an extract of the original Stack Overflow Documentation
Lizenziert unter CC BY-SA 3.0
Nicht angeschlossen an Stack Overflow