Activité 1- Exercice Chapitre 2
Exercice 1- fork() et exec()
1. la fonction fork()
La fonction fork() est un appel système qui permet de créer un nouveau appelé le fils
en créant une copie quasi-identique du processus appelant (le père) en retournant une
valeur de 0 au processus fils et le PID du fils au processus père. Ensuite, les deux
processus continuent l'exécution de l'instruction qui suit immédiatement le fork().
2. La différence entre fork() et exec()
fork sert à dupliquer un processus, tandis que exec sert à lancer une application
différente au sein d'un processus existant. Souvent, on utilise les deux ensemble : on
fait un fork() pour créer un clone, puis le fils fait un exec() pour devenir un autre
programme en exécutant un code différent et en remplaçant totalement l’espace
mémoire.
3. Exemple
#include <stdio.h>
#include <unistd.h>
#include <sys/wait.h>
int main() {
int nombre = 100; // Une variable initialisée à 100
pid_t pid;
printf("Avant le fork, le nombre est : %d\n", nombre);
pid = fork(); // Duplication du processus ici
if (pid == 0) {
// --- PROCESSUS FILS ---
// Le fils modifie SA copie de la variable
nombre = nombre + 50;
printf("[FILS] J'ai ajouté 50. Mon nombre = %d\n",
nombre);
}
else {
// --- PROCESSUS PÈRE ---
wait(NULL); // Le père attend que le fils finisse pour que
l'affichage soit ordonné
// Le père lit SA variable
printf("[PÈRE] Mon fils a fini. Mon nombre = %d\n",
nombre);
}
return 0;
}
1|Page
Exercice 2- Gestion des processus
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/wait.h>
int main() {
pid_t pid1, pid2;
int status1, status2;
// Premier fork : enfant 1
pid1 = fork();
if (pid1 < 0) {
perror("Erreur fork enfant 1");
exit(EXIT_FAILURE);
}
if (pid1 == 0) {
// Code de l'enfant 1
execlp("ls", "ls", "-l", (char *)NULL);
perror("Erreur execlp enfant 1");
exit(EXIT_FAILURE);
}
// Deuxième fork : enfant 2
pid2 = fork();
if (pid2 < 0) {
perror("Erreur fork enfant 2");
exit(EXIT_FAILURE);
}
if (pid2 == 0) {
// Code de l'enfant 2
execlp("ps", "ps", "aux", (char *)NULL);
perror("Erreur execlp enfant 2");
exit(EXIT_FAILURE);
}
// Code du parent : attendre les deux enfants
pid_t wpid;
wpid = waitpid(pid1, &status1, 0);
if (wpid == pid1) {
if (WIFEXITED(status1)) {
printf("Enfant 1 (PID=%d) terminé avec code %d\n", pid1,
WEXITSTATUS(status1));
} else {
printf("Enfant 1 (PID=%d) terminé anormalement\n", pid1);
}
}
wpid = waitpid(pid2, &status2, 0);
if (wpid == pid2) {
if (WIFEXITED(status2)) {
printf("Enfant 2 (PID=%d) terminé avec code %d\n", pid2,
WEXITSTATUS(status2));
} else {
printf("Enfant 2 (PID=%d) terminé anormalement\n", pid2);
}
}
return 0;
}
2|Page
Exercice 3- Threads et synchronisation
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
// Variable globale partagée (Ressource critique)
int compteur = 0;
// Déclaration du mutex
pthread_mutex_t verrou;
// Fonction exécutée par le thread 1 (Incrémentation)
void* incrementer(void* arg) {
for (int i = 0; i < 1000; i++) {
// Début de la section critique : on verrouille
pthread_mutex_lock(&verrou);
compteur++;
// Fin de la section critique : on déverrouille
pthread_mutex_unlock(&verrou);
}
return NULL;
}
// Fonction exécutée par le thread 2 (Décrémentation)
void* decrementer(void* arg) {
for (int i = 0; i < 1000; i++) {
// Début de la section critique : on verrouille
pthread_mutex_lock(&verrou);
compteur--;
// Fin de la section critique : on déverrouille
pthread_mutex_unlock(&verrou);
}
return NULL;
}
int main() {
pthread_t thread1, thread2;
// 1. Initialisation du mutex
if (pthread_mutex_init(&verrou, NULL) != 0) {
printf("Échec de l'initialisation du mutex\n");
return 1;
}
// 2. Création des threads
// On lance l'incrémentation et la décrémentation
if (pthread_create(&thread1, NULL, incrementer, NULL) != 0) {
return 2;
}
if (pthread_create(&thread2, NULL, decrementer, NULL) != 0) {
return 3;
}
3|Page
// 3. Attente de la fin des threads (Join)
// Le main attend que t1 et t2 aient fini leur travail
pthread_join(thread1, NULL);
pthread_join(thread2, NULL);
// 4. Destruction du mutex (Nettoyage)
pthread_mutex_destroy(&verrou);
// 5. Affichage du résultat
// Le résultat DOIT être 0 (0 + 1000 - 1000)
printf("Valeur finale du compteur : %d\n", compteur);
return 0;
}
Exercice 4- Communication par tube (pipe)
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/wait.h>
#define N 5 // Taille du tableau
int main() {
int pipe_p_vers_e[2]; // Pipe 1 : Parent -> Enfant
int pipe_e_vers_p[2]; // Pipe 2 : Enfant -> Parent
int tableau[N] = {10, 20, 30, 40, 50};
int somme_calculee = 0;
int somme_recue = 0;
// 1. Création des deux pipes
if (pipe(pipe_p_vers_e) == -1 || pipe(pipe_e_vers_p) == -1) {
perror("Erreur création pipe");
return 1;
}
// 2. Création du processus
pid_t pid = fork();
if (pid < 0) {
perror("Erreur fork");
return 1;
}
// --- CODE DU FILS ---
if (pid == 0) {
// A. Fermeture des extrémités inutiles
// Le fils LIT sur le pipe 1 et ÉCRIT sur le pipe 2
close(pipe_p_vers_e[1]); // On ferme l'écriture du pipe 1
close(pipe_e_vers_p[0]); // On ferme la lecture du pipe 2
int tampon[N]; // Buffer pour recevoir le tableau
// B. Lecture du tableau envoyé par le parent
read(pipe_p_vers_e[0], tampon, sizeof(int) * N);
printf("[FILS] Tableau reçu. Calcul en cours...\n");
4|Page
// C. Calcul de la somme
for (int i = 0; i < N; i++) {
somme_calculee += tampon[i];
}
// D. Envoi du résultat au parent
write(pipe_e_vers_p[1], &somme_calculee, sizeof(int));
printf("[FILS] Somme envoyée : %d. Fin du processus fils.\n",
somme_calculee);
// E. Fermeture finale
close(pipe_p_vers_e[0]);
close(pipe_e_vers_p[1]);
exit(0);
}
// --- CODE DU PARENT ---
else {
// A. Fermeture des extrémités inutiles
// Le parent ÉCRIT sur le pipe 1 et LIT sur le pipe 2
close(pipe_p_vers_e[0]); // On ferme la lecture du pipe 1
close(pipe_e_vers_p[1]); // On ferme l'écriture du pipe 2
// B. Envoi du tableau au fils
printf("[PARENT] Envoi du tableau au fils...\n");
write(pipe_p_vers_e[1], tableau, sizeof(int) * N);
// C. Lecture de la réponse (somme)
read(pipe_e_vers_p[0], &somme_recue, sizeof(int));
// D. Affichage du résultat final
printf("[PARENT] Somme reçue du fils : %d\n", somme_recue);
// E. Attente de la fin du fils et fermeture finale
wait(NULL);
close(pipe_p_vers_e[1]);
close(pipe_e_vers_p[0]);
}
return 0;
}
5|Page