Tuer un processus enfant en C
-
Utilisez le signal
SIGKILL
pour terminer un processus enfant en C -
Utiliser le signal
SIGTERM
pour terminer un processus enfant en C
Cet article présente plusieurs méthodes sur la façon de tuer un processus enfant dans C.
Utilisez le signal SIGKILL
pour terminer un processus enfant en C
Il existe plusieurs signaux conçus pour terminer un processus lors de sa livraison, mais l’envoi du signal SIGKILL
est la méthode la plus puissante et la plus sûre pour le faire. Généralement, un programme peut enregistrer des fonctions spéciales appelées gestionnaires de signaux qui sont invoquées automatiquement une fois que le signal correspondant est délivré au programme. L’utilisateur implémente le code de fonction du gestionnaire qui effectue généralement des travaux de nettoyage pour le programme. Outre les gestionnaires de fonctions, il peut y avoir des actions par défaut sur les signaux délivrés comme le blocage et l’ignorance. Cependant, le signal SIGKILL
ne peut pas être ignoré, bloqué ou traité par la fonction donnée. Ainsi, cette méthode doit être le dernier recours lorsque vous essayez de terminer un processus.
Le signal SIGKILL
peut être envoyé avec un appel système kill
. Notez cependant que le gestionnaire SIGTERM
inscrit dans l’exemple de code suivant ne peut pas attraper le SIGKILL
livré, et il tue immédiatement le processus enfant donné.
Le programme suivant engendre un processus enfant et y inscrit le gestionnaire SIGTERM
. Ensuite, le processus fils exécute une boucle infinie à moins que le signal ne soit délivré, ce qui retourne la variable d’expression while
. Par conséquent, le signal SIGKILL
délivré par le parent n’invoque pas le gestionnaire et termine instantanément le processus fils.
#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);
}
Utiliser le signal SIGTERM
pour terminer un processus enfant en C
Alternativement, un processus fils peut être arrêté en utilisant le signal SIGTERM
, qui peut être géré par le programme. L’échantillon de code suivant répète l’implémentation du programme précédent sauf qu’il remplace le signal SIGKILL
par SIGTERM
. La fonction sigfillset
est utilisée pour empêcher d’autres signaux d’interrompre l’exécution de la fonction de gestionnaire enregistrée. Le code du gestionnaire modifie la variable globale de type sig_atomic_t
qui arrête la boucle while
dans le processus fils et imprime la valeur de la variable count
. Attention cependant, il est toujours préférable d’utiliser l’appel sigaction
au-dessus de la fonction signal
lors de l’enregistrement des gestionnaires, car cette dernière n’est pas spécifiée en détail par le 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