Gestione del segnale in Linux tramite la funzione signal().
Nella parte 1 di questa serie sui segnali di Linux, abbiamo discusso i fondamenti dei segnali in Linux. In questo articolo discuteremo gli aspetti pratici della gestione del segnale in Linux tramite segnale() funzione. Tutte le spiegazioni saranno accompagnate da esempi pratici.

Gestori di segnali
Un gestore di segnale è una funzione speciale (definita nel codice del programma software e registrata nel kernel) che viene eseguita quando arriva un determinato segnale. Ciò causa l’interruzione del processo di esecuzione corrente e vengono salvati anche tutti i registri correnti. Il processo sospeso riprende una volta che il gestore del segnale ritorna.
La funzione signal().
Il modo più semplice per registrare la funzione di gestione del segnale con il kernel è usare segnale() funzione.
Ecco la sua sintassi segnale() funzione:
#include <signal.h>
typedef void (*sighandler_t)(int);
sighandler_t signal(int signum, sighandler_t handler);
Quindi puoi vedere che un gestore di segnale è una funzione che accetta un argomento intero ma restituisce void. Il gestore del segnale può essere registrato con il kernel usando segnale() funzione (descritta sopra) che accetta un numero di segnale specifico e un nome di funzione di gestione del segnale (sebbene possano esserci altri valori per il secondo argomento, ma ne parleremo più avanti).
Ecco un esempio funzionante di gestione del segnale in Linux tramite segnale() funzione:
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <unistd.h>
void sig_handler(int sig_num)
{
if(sig_num == SIGINT)
{
printf("n Caught the SIGINT signaln");
}
else
{
printf("n Caught the signal number [%d]n", sig_num);
}
// Do all the necessary clean-up work here
exit(sig_num);
}
int main(void)
{
//Register signal handler through the signal() function
signal(SIGINT, sig_handler);
while(1)
{
//simulate a delay -- as if the program is doing some other stuff
sleep(1);
}
return 0;
}
Nel codice del programma mostrato sopra:
- All’interno della funzione main(), la funzione signal() viene utilizzata per registrare un gestore (sig_handler()) per SIGINT segnale.
- Il ciclo while simula un ritardo infinito. Quindi il programma è in attesa CARTELLO segnale all’infinito.
- Il gestore di segnale “sig_handler” stampa un’istruzione di debug controllando se il segnale desiderato lo è SIGINT o no.
- Il gestore del segnale viene utilizzato principalmente per eseguire tutte le operazioni di pulizia e correlate dopo che un segnale è stato consegnato a un processo.
Ecco l’output di questo programma:
$ ./sig_example
^C
Caught the SIGINT signal
Quindi puoi vedere che il programma (sig_example) è stato eseguito e quindi il segnale SIGINT viene trasmesso premendo la combinazione di tasti Ctrl+c. Come si può vedere dall’output di debug, il gestore del segnale è stato eseguito non appena il signal SIGINT è stato consegnato al processo.
Disposizione di un segnale
Per comprendere il concetto di disposizione di un segnale, rivediamo la dichiarazione della funzione del segnale:
sighandler_t signal(int signum, sighandler_t handler);
Il secondo argomento della funzione signal() è noto come disposizione di un segnale. A partire da ora, abbiamo appreso che il secondo argomento è una funzione di gestione del segnale, ma questo non è l’unico tipo di metodo di disposizione del segnale. Altri modi per smaltire il segnale aa sono da specificare SIG_IGN o SIG_DFL come secondo argomento della funzione segnale.
Se la disposizione è impostata su SIG_IGN quindi il segnale (passato come primo argomento a segnale() function) viene ignorato e non consegnato al processo, ma se la disposizione è impostata su SIG_DFL quindi viene intrapresa l’azione predefinita corrispondente a quel segnale.
Ecco un codice di esempio che ignora il codice SIGINT segnale:
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <unistd.h>
int main(void)
{
//Register signal handler through the signal() function
signal(SIGINT, SIG_IGN);
while(1)
{
//simulate a delay -- as if the program is doing some other stuff
sleep(1);
}
return 0;
}
Quindi puoi vedere che ora non esiste alcuna funzione di gestore del segnale perché il secondo argomento della funzione del segnale è sostituito da SIG_IGN.
Ecco l’output di questo programma:
$ ./sig_example
^C^C^C^C^C^C^C^C^C^C^C^C^C^C^C^C^C^C^C^C
Quindi puoi vederlo nonostante le ripetute pressioni Ctrl+c, il processo non è stato influenzato in alcun modo. Questo perché il segnale SIGINT (generato quando Ctrl+c viene premuto) viene ignorato.
Allo stesso modo, ecco un codice di programma che lascia SIGINT alla sua azione predefinita:
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <unistd.h>
int main(void)
{
//Register signal handler through the signal() function
signal(SIGINT, SIG_DFL);
while(1)
{
//simulate a delay -- as if the program is doing some other stuff
sleep(1);
}
return 0;
}
Quindi puoi vedere che il secondo argomento della funzione signal (nel codice mostrato sopra) è sostituito da SIG_DFL in questo caso.
Ed ecco il risultato di questo programma:
$ ./sig_example
^C
$
Quindi puoi vedere quella pressione Ctrl+c ha terminato il processo perché l’azione predefinita a SIGINT è terminare il processo.
Limitazioni della funzione signal().
Sebbene segnale() La funzione è il modo più antico e più semplice per gestire i segnali, presenta alcune limitazioni importanti:
- Altri segnali non sono bloccati dalla funzione signal() mentre il gestore del segnale viene eseguito per il segnale corrente. Questo può produrre risultati indesiderati.
- L’azione del segnale per un particolare segnale viene ripristinata al suo valore predefinito, ovvero, SIG_DFL non appena viene inviato il segnale. Ciò significa che anche se il gestore del segnale imposta nuovamente l’azione del segnale come primo passaggio, esiste una possibile finestra temporale in cui il segnale può verificarsi di nuovo mentre la sua azione è impostata su SIG_DFL.
A causa di queste importanti limitazioni, ora si consiglia di utilizzare la funzione sigazione() che supera tutti questi limiti.