Uccidi un processo figlio in C
-
Usa il segnale
SIGKILL
per terminare un processo figlio in C -
Usa il segnale
SIGTERM
per terminare un processo figlio in C
Questo articolo mostrerà più metodi su come uccidere un processo figlio in C.
Usa il segnale SIGKILL
per terminare un processo figlio in C
Ci sono più segnali progettati per terminare un processo al momento della sua consegna, ma l’invio del segnale SIGKILL
è il metodo più potente e sicuro per farlo. In genere, un programma può registrare funzioni speciali chiamate gestori di segnali che vengono richiamati automaticamente una volta che il segnale corrispondente viene consegnato al programma. L’utente implementa il codice della funzione del gestore che di solito esegue alcune operazioni di pulizia per il programma. Oltre ai gestori di funzioni, ci possono essere azioni predefinite sui segnali forniti come il blocco e l’ignoranza. Tuttavia, il segnale SIGKILL
non può essere ignorato, bloccato o gestito dalla funzione data. Pertanto, questo metodo dovrebbe essere l’ultima risorsa quando si tenta di terminare un processo.
Il segnale SIGKILL
può essere inviato con una chiamata di sistema kill
. Nota però, il gestore SIGTERM
registrato nel seguente esempio di codice non può catturare il SIGKILL
consegnato, e uccide immediatamente il dato processo figlio.
Il seguente programma genera un processo figlio e vi registra il gestore SIGTERM
. Quindi, il processo figlio esegue un bucle infinito a meno che il segnale non venga consegnato, il che capovolge la variabile di espressione while
. Di conseguenza, il segnale SIGKILL
fornito dal genitore non richiama il gestore e termina istantaneamente il processo figlio.
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/wait.h>
#include <unistd.h>
volatile sig_atomic_t shutdown_flag = 1;
void cleanupRoutine(int signal_number) { shutdown_flag = 0; }
int main(void) {
int wstatus;
pid_t c_pid = fork();
if (c_pid == -1) {
perror("fork");
exit(EXIT_FAILURE);
}
if (c_pid == 0) {
printf("printed from child process - %d\n", getpid());
int count = 0;
struct sigaction sigterm_action;
memset(&sigterm_action, 0, sizeof(sigterm_action));
sigterm_action.sa_handler = &cleanupRoutine;
sigterm_action.sa_flags = 0;
// Mask other signals from interrupting SIGTERM handler
if (sigfillset(&sigterm_action.sa_mask) != 0) {
perror("sigfillset");
exit(EXIT_FAILURE);
}
// Register SIGTERM handler
if (sigaction(SIGTERM, &sigterm_action, NULL) != 0) {
perror("sigaction SIGTERM");
exit(EXIT_FAILURE);
}
while (shutdown_flag) {
count += 1;
}
printf("count = %d\n", count);
exit(EXIT_SUCCESS);
} else {
printf("printed from parent process - %d\n", getpid());
int ret;
sleep(5);
ret = kill(c_pid, SIGKILL);
if (ret == -1) {
perror("kill");
exit(EXIT_FAILURE);
}
if (waitpid(c_pid, &wstatus, WUNTRACED | WCONTINUED) == -1) {
perror("waitpid");
exit(EXIT_FAILURE);
}
}
exit(EXIT_SUCCESS);
}
Usa il segnale SIGTERM
per terminare un processo figlio in C
In alternativa, un processo figlio può essere terminato utilizzando il segnale SIGTERM
, che può essere gestito dal programma. L’esempio di codice successivo ripete l’implementazione del programma precedente tranne per il fatto che sostituisce il segnale SIGKILL
con SIGTERM
. La funzione sigfillset
viene utilizzata per impedire che altri segnali interrompano l’esecuzione della funzione handler registrata. Il codice del gestore modifica la variabile di tipo globale sig_atomic_t
che interrompe il cicli while
nel processo figlio e stampa il valore della variabile count
. Attenzione però, è sempre meglio usare la chiamata sigaction
sopra la funzione signal
quando si registrano i gestori, poiché quest’ultima non è specificata in dettaglio dallo standard POSIX.
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/wait.h>
#include <unistd.h>
volatile sig_atomic_t shutdown_flag = 1;
void cleanupRoutine(int signal_number) { shutdown_flag = 0; }
int main(void) {
int wstatus;
pid_t c_pid = fork();
if (c_pid == -1) {
perror("fork");
exit(EXIT_FAILURE);
}
if (c_pid == 0) {
printf("printed from child process - %d\n", getpid());
int count = 0;
struct sigaction sigterm_action;
memset(&sigterm_action, 0, sizeof(sigterm_action));
sigterm_action.sa_handler = &cleanupRoutine;
sigterm_action.sa_flags = 0;
// Mask other signals from interrupting SIGTERM handler
if (sigfillset(&sigterm_action.sa_mask) != 0) {
perror("sigfillset");
exit(EXIT_FAILURE);
}
// Register SIGTERM handler
if (sigaction(SIGTERM, &sigterm_action, NULL) != 0) {
perror("sigaction SIGTERM");
exit(EXIT_FAILURE);
}
while (shutdown_flag) {
count += 1;
}
printf("count = %d\n", count);
exit(EXIT_SUCCESS);
} else {
printf("printed from parent process - %d\n", getpid());
int ret;
sleep(5);
ret = kill(c_pid, SIGTERM);
if (ret == -1) {
perror("kill");
exit(EXIT_FAILURE);
}
if (waitpid(c_pid, &wstatus, WUNTRACED | WCONTINUED) == -1) {
perror("waitpid");
exit(EXIT_FAILURE);
}
}
exit(EXIT_SUCCESS);
}
Founder of DelftStack.com. Jinku has worked in the robotics and automotive industries for over 8 years. He sharpened his coding skills when he needed to do the automatic testing, data collection from remote servers and report creation from the endurance test. He is from an electrical/electronics engineering background but has expanded his interest to embedded electronics, embedded programming and front-/back-end programming.
LinkedIn Facebook