🕒 : 3 h maximum
Prérequis:
But
- Comprendre les signaux et leurs gestionnaires.
- Utiliser
alarm()pour des temporisations. - Travailler avec
sigactionpour une gestion robuste.
Répertoire du travail:
~/Works/TP_C_Signaux
Exercice 1_0 : Capture de SIGINT (Ctrl+C) avec signal
répertoire : ex1, code ex1.c
But : Empêcher Ctrl+C de terminer le programme.
#include <stdio.h>
#include <signal.h>
#include <unistd.h>
void handle_sigint(int sig) {
/* signal(SIGINT, handle_sigint); */ /* relance */
printf("\nTu as appuyé sur Ctrl+C ! Mais je ne quitte pas.\n");
}
int main() {
signal(SIGINT, handle_sigint);
printf("Appuie sur Ctrl+C...\n");
while (1) sleep(1);
return 0;
}
Questions :
Que se passe-t-il si vous appuyez une fois puis plusieurs fois sur Ctrl+C ?
On va dé-commenter la ligne 6 , pour réarmer !
Que se passe-t-il si vous appuyez plusieurs fois sur Ctrl+C?
tester les commandes dans un autre terminal a coté de votre code lancé.
cours sur les processus sous linux
trouver un PID
pidof ex1
autrement
ps -aux | grep ex1
on peut envoyer des signaux avec kill
kill -SIGINT PIDXXXX # déterminer avant
#ou
kill -2 PIDXXXX
Et tester le signal -SIGTERM ou -15
et tester le signal -SIGKILL ou -9
Exercice 1_1 sleep et pause
| Fonction | Comportement |
|---|---|
pause() | Attend indéfiniment un signal. Ne retourne que lorsqu’un signal est reçu. |
sleep(5) | Attend 5 secondes max, mais peut être interrompu par un signal (retourne le temps restant). |
répertoire ex1, code : ex1_1.c
#include <stdio.h>
#include <signal.h>
#include <unistd.h>
void handle_sigint(int sig) {
printf("\nSignal SIGINT reçu (Ctrl+C) !\n");
}
int main() {
signal(SIGINT, handle_sigint);
printf("Appuyez sur Ctrl+C pendant sleep(5)...\n");
int temps_restant = sleep(5); // ← Remplacé pause() par sleep(5)
if (temps_restant > 0) {
printf("sleep() interrompu. Temps restant : %d sec\n", temps_restant);
} else {
printf("sleep() terminé naturellement.\n");
}
while (1); // Pour garder le programme actif
return 0;
}
Questions :
Tester avec sleep(5)
Tester en remplaçant sleep(5) par pause()
Donner les différence entre sleep(5) et pause()
Exercice 1_2 avec sigaction
répertoire ex1, code : ex1_2.c
#include <stdio.h>
#include <signal.h>
#include <unistd.h>
#include <string.h>
void handle_sigint(int sig) {
const char *msg = "\nCtrl+C bloqué ! (Avec sigaction, c'est fiable)\n";
write(STDOUT_FILENO, msg, strlen(msg)); // write() est async-safe
}
int main() {
struct sigaction sa;
memset(&sa, 0, sizeof(sa));
sa.sa_handler = handle_sigint;
sigemptyset(&sa.sa_mask); // Aucun signal bloqué pendant l'exécution
sa.sa_flags = SA_RESTART; // Options : redémarre les appels système interrompus
// Associer le gestionnaire à SIGINT
if (sigaction(SIGINT, &sa, NULL) == -1) {
perror("Erreur sigaction");
return 1;
}
printf("Appuyez sur Ctrl+C... (PID: %d)\n", getpid());
while (1) pause();
return 0;
}
Question:
Comment en sortir?
Exercice 2 : Compteur avec alarm()
But : Utiliser alarm() pour afficher un message toutes les 2 secondes.
Répertoire : ex2 , code : alarm.c
#include <stdio.h>
#include <signal.h>
#include <unistd.h>
void handle_alarm(int sig) {
printf("ALARME ! (2 secondes passées)\n");
alarm(2); // Reprogramme l'alarme
}
int main() {
signal(SIGALRM, handle_alarm);
alarm(2); // Première alarme dans 2s
printf("Compteur démarré (Ctrl+C pour quitter).\n");
while (1) pause(); // Attend les signaux
return 0;
}
Questions :
Que se passe-t-il si vous remplacez pause() par sleep(5) ?
Ajoutez un compteur global pour afficher le nombre d’alarmes déclenchées.
Exercice 3 : Blocage de signaux avec sigprocmask()
But : Bloquer temporairement SIGINT pendant une opération critique.
Répertoire : ex3 , code: sigprocmask.c
#include <stdio.h>
#include <signal.h>
#include <unistd.h>
void handle_sigint(int sig) {
printf("SIGINT reçu, mais ignoré pendant le calcul.\n");
}
int main() {
sigset_t mask;
signal(SIGINT, handle_sigint);
// Bloquer SIGINT
sigemptyset(&mask);
sigaddset(&mask, SIGINT);
sigprocmask(SIG_BLOCK, &mask, NULL);
printf("Calcul critique en cours (5s)...\n");
sleep(5);
// Débloquer SIGINT
sigprocmask(SIG_UNBLOCK, &mask, NULL);
printf("Calcul terminé. Ctrl+C fonctionne à nouveau.\n");
while (1) pause();
return 0;
}
Questions :
Testez en appuyant sur Ctrl+C pendant le sleep(5). Que se passe-t-il ?
Utilisez sigpending() pour afficher les signaux en attente.
Exercie 4 : signal SIGUSR1
Signaux SIGUSR1 et SIGUSR2 : Origine et Utilité
Les signaux SIGUSR1 (10) et SIGUSR2 (12) sont deux signaux définis par l’utilisateur dans les systèmes Unix/Linux. Contrairement aux signaux standards comme SIGINT (Ctrl+C) ou SIGKILL, ils n’ont aucun comportement prédéfini et sont entièrement customisables par le programmeur.
Répertoire: ex4 , code : sigusr1.c
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <unistd.h>
// Variable globale pour contrôler la boucle principale
volatile sig_atomic_t stop = 0;
// Gestionnaire de signal
void handle_sigusr1(int sig) {
if (sig == SIGUSR1) {
printf("Signal SIGUSR1 reçu. Arrêt demandé.\n");
stop = 1; // On modifie le drapeau pour sortir de la boucle
}
}
int main() {
// Affiche le PID pour qu'on puisse envoyer le signal
printf("Mon PID est : %d\n", getpid());
printf("Envoyez 'kill -SIGUSR1 %d' depuis un autre terminal pour m'arrêter.\n", getpid());
// Configuration du gestionnaire de signal
signal(SIGUSR1, handle_sigusr1);
// Boucle principale
while (!stop) {
printf("En attente... (Ctrl+C pour quitter immédiatement)\n");
sleep(1); // Réduit la consommation CPU
}
printf("Arrêt propre du programme.\n");
return 0;
}
Questions :
