TD 71
TD 71
TD 71
Un signal masqué est un signal qui a été envoyé à un processus, mais qui ne sera pas pris en
compte immédiatement par celui-ci. Lorsqu'un signal est masqué, il est mis en attente jusqu'à
ce que le processus démasque le signal et permette ainsi son traitement.
Lorsque plusieurs occurrences d’un signal sont envoyées à un processus qui a ce signal
masqué, ces signaux sont stockés en mémoire. En fonction du type de signal, il est possible
qu'il y ait un mécanisme de fusion (par exemple, pour SIGCHLD) ou de simple mise en file
d'attente. Lorsque le signal est à nouveau autorisé, il est traité, mais il peut ne pas être traité
autant de fois que d'occurrences, suivant la nature du signal.
1. Ctrl-C envoie un signal SIGINT : Correct, Ctrl-C génère un signal SIGINT pour
interrompre le programme en cours.
2. Envoyer un signal SIGKILL termine immédiatement le processus : Correct,
SIGKILL termine un processus immédiatement sans possibilité de gestion ou de
récupération.
3. SIGTERM ou SIGKILL pour terminer proprement : Incorrect, SIGTERM peut être
intercepté par le processus et lui permettre de se terminer proprement, mais SIGKILL
ne peut pas être intercepté et tue immédiatement le processus sans possibilité de
nettoyage.
4. Ctrl-C envoie un signal SIGTERM : Incorrect, Ctrl-C envoie le signal SIGINT, pas
SIGTERM.
Le système d'exploitation envoie ce signal au processus. Il n'est pas forcément fatal, car le
processus peut installer un gestionnaire de signal pour traiter l'erreur. Toutefois, dans la
plupart des cas, le signal mène à l'arrêt du processus, à moins qu'un gestionnaire de signal ne
soit installé pour éviter la terminaison immédiate.
Si le gestionnaire prend plus de temps que l'intervalle entre les signaux, les
signaux risquent d'être "perdus" si le signal est envoyé avant la fin de l'exécution du
gestionnaire.
Si vous réautorisez la délivrance du signal avec sigprocmask à l’intérieur du
gestionnaire, le signal sera remis dans la file d'attente et traité plus tard. Cela peut
entraîner une exécution répétée du gestionnaire de signal.
Un signal n'est délivré à un processus que lorsque celui-ci est dans un état où il peut traiter
le signal, c’est-à-dire lorsqu'il est en mode "exécution" ou dans certains autres états
spécifiques (par exemple, un processus dans pause() ou sleep() peut recevoir un signal).
Un processus dans une boucle infinie (comme while(1);) continue d'exécuter des
instructions et peut donc recevoir des signaux, car il est en mode "exécution". Il est donc
possible qu'un processus en boucle infinie reçoive un signal, bien que certains types de signal
(comme SIGALRM) ne soient envoyés que lorsque le processus "attend" un événement
spécifique.
Dans ce programme, l'erreur principale est que la variable counter est modifiée à la fois dans
la boucle principale du programme et dans le gestionnaire de signal. Cela peut entraîner des
problèmes de concurrence.
Il est nécessaire de déclarer la variable counter comme sig_atomic_t pour
garantir que son accès est sûr lors du traitement des signaux. Cela permet de prévenir
les problèmes d'accès concurrent aux variables globales utilisées dans des
gestionnaires de signaux.
La déclaration volatile ne suffira pas dans ce cas car cela n'évitera pas les problèmes de
modification simultanée par le gestionnaire et la boucle principale.
La solution avec une queue de signaux permet de stocker tous les signaux envoyés à
un processus. Cependant, cela peut entraîner une surcharge mémoire si trop de signaux
sont envoyés.
La solution avec drapeaux binaires est plus économe en mémoire (un bit par signal),
mais elle peut entraîner la perte de certains signaux si plusieurs signaux sont envoyés
avant qu'un signal soit traité.
Voici un exemple de programme pour masquer et rétablir les signaux SIGINT et SIGQUIT
pendant 30 secondes :
c
Copier le code
#include <stdio.h>
#include <signal.h>
#include <unistd.h>
int main() {
sigset_t set;
Voici un exemple de programme qui fait ping-pong entre un processus père et son processus
fils, en envoyant alternativement SIGUSR1 et SIGUSR2 :
c
Copier le code
#include <stdio.h>
#include <signal.h>
#include <unistd.h>
#include <stdlib.h>
pid_t child_pid;
signal(SIGUSR1, handler_usr1);
signal(SIGUSR2, handler_usr2);
child_pid = fork();
if (child_pid == 0) {
// Code du fils
for (int i = 0; i < count; i++) {
pause(); // Attendre un signal
}
} else {
// Code du père
for (int i = 0; i < count; i++) {
kill(child_pid, SIGUSR1);
pause(); // Attendre un signal
}
}
return 0;
}
Cela couvre tous les exercices demandés. N'hésitez pas si vous avez besoin de précisions
supplémentaires !