TP 2 - Création de processus - Fork
Comme le nom du TP l’indique, vous allez utiliser la fonction système fork
pour créer de nouveaux processus.
Attendu
Vous avez deux séances pour réaliser ce TP.
-
OS_Nom1_Nom2
-
TPFork
-
.gitignore
(avec tout ce qui n’est pas attendu) -
Makefile
-
reponses.md
-
forkWait.c
-
forkGlobales.c
-
forkShared.c
-
forkSharedWait.c
-
forkBonus.c
-
-
Pensez donc bien à effectuer des commit
et des push
régulièrement.
Sujet
L’objectif de ce TP est de vous faire créer et manipuler des processus en C.
Un processus Unix peut en créer un autre grâce à l’appel système fork
. Un processus qui appelle fork
est dupliqué par le système.
Après cette duplication il existe un nouveau processus, appelé processus
enfant qui est une copie exacte du processus initial qui a appelé fork
et
qui est appelé processus parent. L’exécution des deux processus continue en
parallèle après l’appel à fork
. On distingue le parent de l’enfant par la valeur
renvoyée par fork
:
-
dans le processus enfant : 0
-
dans le processus parent : le numéro d’identification (PID) du processus enfant créé
Pour ce TP, vous aurez besoin du document intitulé : "Unix : quelques fonctions système". Les informations données dans ce document sont une synthèse, vous pouvez toujours, pour chaque fonction Unix, lire le manuel en ligne correspondant avec :
man 2 <fonction>
man 3 <fonction>
Mise en place
Vous trouverez un exemple de création d’un processus dans
le fichier fork.c
Compilation
Vous devez créer un Makefile
permettant de compiler ce programme d’exemple
puis les autres que vous réaliserez. Vous êtes notés sur ce Makefile
, poussez-le.
1. Identification et synchronisations simples
Vous ferez les modifications demandées dans votre fichier forkWait.c
.
Vous répondrez aux questions de cette section dans un fichier
reponses.md
.
Ajoutez également ce fichier à votre dépôt GitLab pour qu’il soit pris en compte.
git add responses.md
git commit
git push
1.1. Questions de filiation
Le programme fourni (fork.c
) réalise pour chacun des processus, parent et
enfant, l’affichage de leur PID
et du PID
de leur parent (fonctions getpid
et getppid
). La durée de vie du parent a été rallongée pour permettre laisser
au processus enfant le temps de s’exécuter avant la fin de son parent. Faites
tourner ce programme.
-
Quel est le PID du processus parent ? Quel est le PPID du processus enfant ? Qu’est-ce que cela vous permet de vérifier ?
-
Quel processus est le parent du processus parent ? Retrouvez son nom et son PID avec:
pstree -ps <numéro de processus>
-
Modifiez le programme pour que l’enfant réalise son affichage 4 fois d’affilé avec une pause de 1 seconde entre chaque affichage. Comment évoluent le
PID
et lePPID
du processus enfant une fois que son parent ``naturel'' se termine ? Expliquez ce qui arrive à un processus orphelin et quel processus l’adopte.
1.2. Synchronisations
Vous passerez à un fichier forkSync.c pour cette question.
Afin de mettre en œuvre la synchronisation de processus, vous allez créer deux processus enfants puis attendre la fin de leur exécution et afficher de l’information relative à l’enfant qui se termine.
Commencez par faire en sorte que le processus parent ait deux enfants mais pas de petits-enfants. Ceci n’est pas trivial
Ajoutez des délais d’attente avant la fin des processus enfants.
Faites ensuite en sorte que le parent attende la fin de ses deux enfants et
affiche leurs PID
.
Vous aurez besoin de la fonction wait
. Exécutée par un processus, elle bloque
ce dernier jusqu’à la fin d’un de ses enfants. Si le processus n’a pas d’enfant
actif, wait
renvoie -1, dans le cas contraire, elle renvoie le numéro (PID
)
du processus enfant mort. Les enfants pourront se contenter d’afficher leur PID
.
2. Variables Globales
Cette partie se fera dans un fichier nommé forkGlobales.c
En repartant du fichier fork.c
d’origine, définissez une variable globale de
type entier puis faites en sorte que chaque processus, le parent et l’enfant,
incrémente puis affiche la valeur de cette variable un grand nombre de fois (au
moins 100). Assurez vous à l’aide d’affichages que les deux processus accèdent
à la variable globale de manière simultanée en vérifiant que l’un ne se termine
pas avant que l’autre ne commence. Si ce n’est pas le cas, ajoutez des
itérations d’incrément.
-
Y a-t-il interférence entre les deux processus ?
Répondez et expliquez pourquoi dans le fichier reponses.md
, que vous avez ajouté à votre dépôt Git.
Pour finir cette partie, initialisez la valeur de la variable globale à une
valeur particulière (autre que 0) puis ajoutez un affichage permettant de
vérifier que le fork duplique l’espace mémoire du processus parent dans l’état
dans lequel il est au moment du fork
.
3. Fichier Partagé
Vous travaillerez dans un fichier nommé forkShared.c
pour cette partie.
Afin d’expérimenter l’accès à des ressources partagées il vous est demandé de faire en sorte que deux processus accèdent simultanément à un fichier.
Pour cela écrivez un programme qui ouvre un fichier sharedFile.txt
en
écriture puis qui crée un processus enfant. Les deux processus devront
ensuite écrire simultanément dans le fichier une chaîne de votre choix un
grand nombre de fois (~1000 fois).
for (int i = 0; i < 1000; i++) {
fprintf(sharedFile, "Je suis le pere !![%ld:%d]\n", pid, i);
fflush(sharedFile);
}
Faites en sorte que la chaîne écrite par les deux processus soit longue.
Par exemple "Je suis le fiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiils"
. Ou plus long.
Vous ajouterez également un délai avant la première des écritures du parent dans
le fichier pour donner au processus enfant le temps de démarrer avec : usleep(10);
(Expérimentez avec la durée de ce délai).
Lancez plusieurs fois votre programme et observez, dans un éditeur de texte, le
contenu du fichier sharedFile.txt
après chaque lancement (pensez à recharger
le fichier après une exécution de votre programme).
Vous devriez constater un mélange des affichages du parent et de l’enfant.
Vous répondrez aux questions suivantes dans le fichier reponses.md
:
-
Expliquez pourquoi il y a un mélange des affichages. (Si ce n’est pas le cas, allongez les chaînes, modifiez le délai de démarrage de l’affichage du parent)
Pour l’ouverture du fichier, vous utiliserez la fonction fopen
et le mode “w”
.
FILE* sharedFile = fopen("./sharedFile.txt", "w");
Pour écrire dans le fichier, vous utiliserez la fonction fprintf
.
4. Fichier Partagé et synchronisation
Vous travaillerez dans un fichier nommé forkSharedWait.c
pour cette partie.
Afin d’éviter le mélange des affichages, vous allez ouvrir le fichier une fois les processus créés puis synchroniser les processus
Dans la question précédente, l’ouverture du fichier partagé se fait, si vous avez
respecté les consignes, avant la création du processus enfant. Déplacez
l’ouverture du fichier pour qu’elle ait lieu après la création de l’enfant, après
le fork
donc.
Attendez que le processus enfant ait terminé son exécution avant de commencer les affichages du parent.
Vous prendrez soin de numéroter les affichages pour vérifier qu’ils ont tous lieu. Inspirez vous de l’exemple de code ci-dessus.
Vous répondrez aux questions suivantes dans le fichier reponses.md
:
-
Constatez-vous toujours un mélange des affichages ?
-
Est-ce que les affichages des deux processus, notamment ceux du processus enfant, apparaissent dans le fichier ? Expliquez pourquoi.
Pour que les affichages du processus enfant apparaissent, utilisez le mode
d’ouverture "a"
uniquement pour le parent.
Vérifiez que les affichages de l’enfant apparaissent bien dans le fichier partagé.
5. Bonus
Vous travaillerez dans un fichier nommé forkBonus.c
pour cette partie.
Faites Exécuter la commande ps -fU <votreLogin>
dans un processus enfant.
Vous aurez besoin de la fonction execlp
.
Ajoutez un affichage dans le processus enfant après le execlp
pour indiquer la fin du programme ps
.
-
Pourquoi cet affichage n’apparaît jamais ?
Ajoutez enfin un affichage dans le processus parent indiquant la fin de l’exécution de ps
.
6. Compte-rendu
Pensez à vérifier que vous avez bien poussé votre dernière version des fichiers demandés.
-
OS_Nom1_Nom2
-
TPFork
-
.gitignore
(avec tout ce qui n’est pas attendu) -
Makefile
-
reponses.md
-
forkWait.c
-
forkGlobales.c
-
forkShared.c
-
forkSharedWait.c
-
forkBonus.c
-
-