Ricerca…


Sintassi

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

Parametri

Parametro Dettagli
sig Il segnale per impostare il gestore di segnali su SIGABRT , SIGFPE , SIGILL , SIGTERM , SIGINT , SIGSEGV o qualche valore definito dall'implementazione
func Il gestore di segnale, che è uno dei seguenti: SIG_DFL , per il gestore predefinito, SIG_IGN per ignorare il segnale, o un puntatore a funzione con la firma void foo(int sig); .

Osservazioni

L'uso di gestori di segnale con le sole garanzie dello standard C impone varie limitazioni che possono o non possono essere eseguite nel gestore di segnali definito dall'utente.

  • Se la funzione definita dall'utente restituisce durante la gestione di SIGSEGV , SIGFPE , SIGILL o qualsiasi altro interrupt hardware definito dall'implementazione, il comportamento non è definito dallo standard C. Ciò è dovuto al fatto che l'interfaccia di C non fornisce i mezzi per modificare lo stato di errore (ad es. Dopo una divisione di 0 ) e quindi quando restituisce il programma è esattamente lo stesso stato errato di prima dell'interruzione dell'hardware.

  • Se la funzione definita dall'utente è stata chiamata come risultato di una chiamata per abort , o raise , il gestore di segnali non può chiamare di nuovo raise .

  • I segnali possono arrivare nel bel mezzo di qualsiasi operazione, e quindi l'indivisibilità delle operazioni non può generalmente essere garantita né la gestione dei segnali funziona bene con l'ottimizzazione. Pertanto tutte le modifiche ai dati in un gestore di segnali devono essere relative a variabili

    • di tipo sig_atomic_t (tutte le versioni) o un tipo atomico senza blocco (dal C11, opzionale)
    • che sono qualificati volatile .
  • Altre funzioni dalla libreria standard C di solito non rispettano queste restrizioni, perché possono cambiare le variabili nello stato globale del programma. Lo standard C fornisce solo garanzie per l' abort , _Exit (dal C99), quick_exit (dal C11), il signal (per lo stesso numero di segnale) e alcune operazioni atomiche (dal C11).

Il comportamento non è definito dallo standard C se una qualsiasi delle regole precedenti viene violata. Le piattaforme possono avere estensioni specifiche, ma generalmente non sono portatili oltre tale piattaforma.

  • Di solito i sistemi dispongono di una propria lista di funzioni che sono sicure per il segnale asincrono , ovvero delle funzioni della libreria C che possono essere utilizzate da un gestore di segnali. Ad esempio, printf è tra queste funzioni.

  • In particolare, lo standard C non definisce molto l'interazione con la sua interfaccia di thread (dal C11) o alcuna libreria di thread specifica della piattaforma come i thread POSIX. Tali piattaforme devono specificare l'interazione di tali librerie di thread con i segnali da soli.

Gestione dei segnali con "signal ()"

I numeri di segnale possono essere sincroni (come SIGSEGV - errore di segmentazione) quando vengono attivati ​​da un malfunzionamento del programma stesso o asincrono (come SIGINT - attenzione interattiva) quando vengono avviati dall'esterno del programma, ad esempio da un tasto premuto come Cntrl-C .

La funzione signal() è parte dello standard ISO C e può essere utilizzata per assegnare una funzione per gestire un segnale specifico

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

L'uso di signal() impone limitazioni importanti a ciò che si è autorizzati a fare all'interno dei gestori di segnale, vedere le osservazioni per ulteriori informazioni.

POSIX raccomanda l'uso di sigaction() invece di signal() , a causa del suo comportamento sotto-specificato e delle significative variazioni di implementazione. POSIX definisce anche molti più segnali rispetto allo standard ISO C, inclusi SIGUSR1 e SIGUSR2 , che possono essere utilizzati liberamente dal programmatore per qualsiasi scopo.



Modified text is an extract of the original Stack Overflow Documentation
Autorizzato sotto CC BY-SA 3.0
Non affiliato con Stack Overflow