Table des matières
Exercice 1 : Tubes et ce qui va avec ... donc dup2 ...
Pour cet exercice vous devez récupérer sur moodle 3 fichiers: le squelette du programme ``sqexoPi.c`` et les 2 fichiers de test: ``ficPI.txt`` et ``ficPIb.txt``
Question 1
On veut réaliser le programme suivant:
Un processus père génère SEQUENTIELLEMENT N fils (N étant passé en paramètre du programme) et chaque processus fils va rechercher dans un fichier donné (fichier contenant une suite aléatoire de chiffres) une séquence de plus en plus longue des chiffres composant le nombre PI (\(\pi\)): le 1er fils cherchera la chaîne “3” dans le fichier, le 2ème fils cherchera la chaîne “31” dans le fichier, le 3ème fils cherchera la chaîne “314” dans le fichier, et ainsi de suite (le ième fils cherchera la chaîne de longueur i).
La recherche se fera grâce à l’utilisation de la commande «grep -c» qui permettra de connaître la présence ou l’absence de la chaîne dans le fichier et aussi de transmettre cette information au père grâce à un tube.
Le processus père récupèrera au fur et à mesure dans le tube le nombre d’occurrences (1 ou 0) trouvé par chaque fils, et affichera un message donnant l’indice du fils ayant trouvé la plus longue chaîne des chiffres de PI dans le fichier donné et affichant cette séquence la plus longue.
Remarque :
il peut être judicieux d’interrompre la boucle quand une recherche a été «négative».
Le nom du fichier sera aussi passé en paramètre du programme. On vous fournit 2 fichiers: ficPI.txt et ficPIb.txt afin de tester votre programme. Vous partirez du squelette du programme sqexoPi.c qui vous est fourni et vous le copierez dans un autre fichier de nom exoPi1.c
Exemple d’exécution : d’abord avec le fichier ficPI.txt puis avec ficPIb.txt (et 3 proc. fils)
>$ ./exoPi 3 ficPI.txt Fils no 1 va chercher chaine 3 dans fichier PERE : Reponse pour 1 ieme grep : 1 Fils no 2 va chercher chaine 31 dans fichier PERE : Reponse pour 2 ieme grep : 1 Fils no 3 va chercher chaine 314 dans fichier PERE : Reponse pour 3 ieme grep : 1 PERE : c'est mon fils numero 3 qui a trouve la plus longue chaine pour PI, soit : 314 >$./exoPi 3 ficPIb.txt Fils no 1 va chercher chaine 3 dans fichier PERE : Reponse pour 1 ieme grep : 1 Fils no 2 va chercher chaine 31 dans fichier PERE : Reponse pour 2 ieme grep : 0 PERE : c'est mon fils numero 1 qui a trouve la plus longue chaine pour PI, soit : 3 >$
Question 2
Recopiez votre programme précédent exoPi1.c dans un autre fichier de nom ``exoPi2.c``
On veut maintenant modifier le programme précédent afin que les N fils soient créés en parallèle dans une première boucle indépendante du traitement. Pour cela il vous faudra rajouter un 2ème tube. Chaque processus fils \(F_i\) devra se créer 1 fils \(Pf_i\) (donc “petit-fils” du processus père initial) pour lui déléguer la recherche (avec grep), et \(F_i\) récupèrera de \(Pf_i\) le résultat de cette recherche et le renverra, via le 2ème tube, au processus père. Cependant, pour que ceci fonctionne et que le processus père récupère bien le numéro du fils à qui correspond le résultat de la recherche, il faudra transmettre dans le 2ème tube (vous utiliserez l’instruction write()) une structure contenant les 2 informations utiles: l’indice du fils et le résultat de la recherche.
Exemple d’exécution : d’abord avec le fichier ficPI.txt puis avec ficPIb.txt (et 3 proc. fils)
>$ ./exoPi2 3 ficPI.txt Petit-fils no 1 de pid 1459 (et de pere 1456) va chercher chaine 3 dans le fichier Petit-fils no 2 de pid 1460 (et de pere 1457) va chercher chaine 31 dans le fichier Petit-fils no 3 de pid 1461 (et de pere 1458) va chercher chaine 314 dans le fichier FILS 1 de pid 1456: Reponse pour 1 ieme grep : 1 PERE : Reponse lue : no fils 1 (de pid:1456) resultat grep : 1 FILS 2 de pid 1457: Reponse pour 2 ieme grep : 1 PERE : Reponse lue : no fils 2 (de pid:1457) resultat grep : 1 FILS 3 de pid 1458: Reponse pour 3 ieme grep : 1 PERE : Reponse lue : no fils 3 (de pid:1458) resultat grep : 1 PERE : c'est mon fils numero 3 (de pid 1458)qui a trouve la plus longue chaine pour PI, soit : 314 >$ >$ ./exoPi3 3 ficPIb.txt Petit-fils no 1 de pid 908 (et de pere 905) va chercher chaine 3 dans le fichier Petit-fils no 2 de pid 909 (et de pere 906) va chercher chaine 31 dans le fichier Petit-fils no 3 de pid 910 (et de pere 907) va chercher chaine 314 dans le fichier FILS 1 de pid 905: Reponse pour 1 ieme grep : 1 PERE : Reponse lue : no fils 1 (de pid:905) resultat grep : 1 FILS 2 de pid 906: Reponse pour 2 ieme grep : 0 PERE : Reponse lue : no fils 2 (de pid:906) resultat grep : 0 FILS 3 de pid 907: Reponse pour 3 ieme grep : 0 PERE : Reponse lue : no fils 3 (de pid:907) resultat grep : 0 PERE : c'est mon fils numero 1 (de pid 905)qui a trouve la plus longue chaine pour PI, soit : 3 >$
Exercice 2 : Synchronisation de processus avec des signaux
On se propose d’écrire un programme utilisant un processus père et 2 processus fils qui vont travailler en alternance grâce à l’utilisation des signaux SIGUSR1 et SIGUSR2.
- Le processus père crée ses 2 processus fils
- puis le processus père, après s’être endormi 5 secondes, envoie SIGUSR1 au fils n°1 puis se met en attente (de l’arrivée d’un signal)
- le fils n°1 , quand il reçoit SIGUSR1, se met à travailler pendant un temps aléatoire puis, quand il a fini, il envoie à son tour le signal SIGUSR1 au père puis se met en attente (de l’arrivée d’un signal)
- le père, quand il reçoit SIGUSR1, envoie SIGUSR2 au fils n°2 puis se met en attente (de l’arrivée d’un signal)
- le fils n°2 , quand il reçoit SIGUSR2, se met à travailler pendant un temps aléatoire puis, quand il a fini, il envoie à son tour le signal SIGUSR2 au père puis se met en attente (de l’arrivée d’un signal)
- et ainsi de suite …
Enfin, pour que le programme se termine, le processus père, à son démarrage, arme une alarme (grâce à la fonction alarm()) pour déterminer sa fin (par exemple temporisation de 15 secondes). Quand il reçoit le signal SIGALRM (déclenché par la fonction alarm()) il tue ses 2 fils puis se termine.
Remarque :
Pour simuler le « travail » d’un processus fils, celui-ci affichera le message “Processus fils no x (PID xxx) . Je travaille pendant x secondes” puis s’endormira pendant un temps aléatoire (entre 1 et 5 secondes).
Ecrivez le programme que vous nommerez exo2.c qui répond à ces exigences.
Exemple d’exécution :
$ ./exo2Sig FILS 1 (PID 787). J'attends un signal de mon père 786 FILS 2 (PID 788). J'attends un signal de mon père 786 PERE : SIGUSR1 envoye a fils 1 FILS (787): Signal SIGUSR1 (30) bien recu de mon pere 786 FILS 1 (PID 787) . Je travaille pendant 3 sec. PERE 786: Signal SIGUSR1(30) bien recu de mon fils 1 PERE : SIGUSR2 envoye a fils 2 FILS (788): Signal SIGUSR2 (31) bien recu de mon pere 786 FILS 2 (PID 788) . Je travaille pendant 3 sec. PERE 786: Signal SIGUSR2(31) bien recu de mon fils 2 PERE : SIGUSR1 envoye a fils 1 FILS (787): Signal SIGUSR1 (30) bien recu de mon pere 786 FILS 1 (PID 787) . Je travaille pendant 5 sec. PERE 786: Signal SIGALRM(14) bien recu PERE 786: Je termine mes fils : fils 787 et fils 788 PERE 786 : Je me termine $
Exercice 2 : Des chiffres et des lettres chiffres
Dans cet exercice, nous allons simuler un jeu à plusieurs participants à l’aide de processus. Le processus père jouera le rôle d’organisateur et d’arbitre, les processus fils seront les participants. Le principe du jeu est le suivant:
- Dans une première phase, chaque participant tire au hasard un nombre entre 1 et 9 et le communique à l’arbitre.
- Une fois que l’arbitre a récupéré les nombres de tous les participants, il leur indique qu’ils peuvent commencer la phase de calcul.
- Pendant la phase de calcul, chaque participant effectue des opérations aléatoires sur tous les nombres qui ont été tirés, puis une fois le résultat calculé, le transmet à l’arbitre.
- Quand l’arbitre a reçu les résultats de calcul de tous les participants, il annonce le vainqueur comme celui ayant obtenu le résultat le plus grand.
Ce programme de simulation utilisera des objets IPC pour effectuer la synchronisation et l’échange des données. Vous pourrez tester votre programme avec la génération de 4 processus fils.
Question 1
Dans cette première question il vous est demandé de créer le fichier ``exo3_1.c`` afin de réaliser ce la première phase du simulateur: les processus fils tirent au hasard un nombre qu’ils communiquent au processus père. La synchronisation se fera à l’aide d’un groupe de N sémaphores et l’échange des données se fera par une zone de mémoire partagée, homogène à un tableau de N entiers, où chaque processus placera sa valeur dans sa case correspondante. Ainsi toutes les valeurs seront visibles par tous les participants.
Les tâches à réaliser sont donc les suivantes:
- le processus père va générer les N fils,
- les fils placeront le nombre qu’ils ont tiré au hasard (entre 1 et 9) dans la zone de mémoire des valeurs partagées entre tous les processus,
- les fils préviennent le processus père qu’ils ont fini puis se terminent,
- le processus père attend les valeurs puis les affiche.
Question 2
Recopier votre fichier de la question précédente en un nouveau fichier nommé ``exo3_2.c`` que vous modifierez pour répondre à cette question.
Maintenant, la deuxième phase du jeu doit être implantée. Cette deuxième phase comprend la phase de calcul de chaque processus et se place, dans le programme, juste après la phase réalisée dans la question précédente.
- le processus père a reçu les valeurs tirées par les processus fils et les a affichées.
- le processus père donne le top départ pour prévenir les fils que les données sont prêtes et qu’ils peuvent commencer la phase de calcul.
- les fils qui étaient en attente du top du père effectuent leur calcul à partir de la zone de mémoire des valeurs partagées et placeront leur résultat dans la zone de mémoire partagée des résultats.
- les fils préviennent le processus père qu’ils ont fini puis se terminent,
- le processus père attend les résultats puis les affiche et affiche aussi le vainqueur.
Dans cette question il vous faudra introduire un second groupe de sémaphore et une seconde zone de mémoire partagée pour placer les résultats des processus fils.
Note:
Pour la phase de calcul aléatoire, vous pouvez par exemple tirer un nombre au hasard entre 0 et 3 et associer une opération pour chacune des valeurs, par exemple 0:’+’, 1:’-’, 3:’/’, 4:’*’. Pour n valeurs, il y aura n-1 opérations à effectuer pour obtenir un résultat, par exemple 2+4+1/3. Les opérations sont effectuées séquentiellement sans ordre de priorité: ((2+4)+1)/3.
Question 3
La solution précédente présente un problème de tricherie évidente: un participant mal intentionné pourrait s’assurer de répondre en dernier et de simplement renvoyer le résultat maximal présent dans la zone de mémoire des résultats + 1 comme étant le sien.
Afin d’éviter ce désagrément, la seconde phase d’échange de données ne se fera pas par SHM mais par une file de messages. Le contenu du message sera simplement le résultat mais son type sera le numéro du processus plus 1 (entre 1 et N).
Recopier votre fichier précédent en un nouveau fichier nommé ``exo3_3.c``, et modifier celui-ci afin d’implanter cette solution alternative.
Question 4
Dans cette question, le contenu du message sera un peu modifié afin d’envoyer en plus du résultat les opérations effectuées. Les processus devant réaliser N-1 opérations, il sera possible d’utiliser une chaîne de N-1 caractères. Le processus père affichera alors le vainqueur ainsi que la suite d’opérations effectuées et vérifiera que le résultat est bien cohérent avec la chaîne d’opérations. Copier le fichier précédent en un nouveau fichier nommé ``exo3_4.c``, et modifier celui-ci afin d’implanter cette amélioration.
Exemple de trace d’exécution du simulateur avec 2 participants
fils 0 -- tirage de la valeur 3
fils 1 -- tirage de la valeur 7
pere -- valeurs disponibles: 3 7
fils 0 -- resultat envoye: 21, operations: *
fils 1 -- resultat envoye: 10, operations: +
pere -- resultat 21 recu par operation *, validee
pere -- resultat 7 recu par operation +, validee
pere -- vainqueur fils 0 avec la valeur 21 par operation 3*7