Question 1: Donner l'arbre des processus créés par le code suivant : main() { 1 fork(); 2 fork(); 3 fork(); } main - P1 - P4 - P7 | \- P5 | | - P2 - P6 \ - P3 Explication : 8 processus : - le processus main, crée trois processus P1, P2 et P3, respectivement en ligne 1,2 et 3. - le processus P1 créé en ligne 1 crée deux processus P4 et P5 en ligne 2 et 3, P5 a terminé - le processus P2 crée en ligne 2 crée un processus P6 en ligne 3, P6 a terminé. - le processus P3 crée en ligne 3 a terminé - le processus P4 crée un processus P7 en ligne 3. Expliquer les relations père-fils entre les processus à l'aide des numéros de ligne indiqués en face des appels à fork(). Question 2: Ecrire un programme qui crée un processus fils. Le processus fils se mets en pause pendant 20 secondes et se termine (voir la fonction sleep) Le processus père se met en attente du fils et crée un nouveau processus dès que le fils précédent et terminé, après avoir indiqué le code de sortie du processus fils terminé. Observer les processus en activité avec la commande ps ou top ou htop. Que se pass-t-il si vous arrêtez le processus fils avec la commande kill -9 ? Que se passe-t-il si vous arrêtez le processus père alors que le fils est encore en activité ? #include #include #include /* en observant l'arbre des processus et : - en arrêtant le processus père : le fils est rattaché à init. - en arrêtant le processus fils : code de sortie à zéro. et WIFSIGNALED(status) à vrai. - Si le processus fils termine après le sleep, valeur du code de sortie indiquée par l'appel système exit, WIFSIGNALED(status) à faux. */ int main(int argc,char *argv[]) { int pid; do { if ( (pid=fork()) < 0 ) perror("fork"); /* fils, attente de 20 s */ if(pid == 0 ) { sleep(20); exit(10); } /* père, se mets en attente du fils */ /* crée un nouveau processus dès que fils termine : on boucle*/ if(pid > 0) { int status=-1; if(wait(&status)<0) perror("wait"); printf("fils de pid %d terminé, code de sortie %d, signaled %d\n", pid, WEXITSTATUS(status), WIFSIGNALED(status)); } } while (1); } Question 3: Ecrivez un programme qui crée n processus selon la hiérarchie suivante, avec n passé en paramètre : P1--P2 -- ... -- Pn-1 -- Pn #include #include #include #include int main(int argc,char *argv[]) { int status; if(argc < 2 ) { printf("Usage : n_proc \n"); exit(0); } int n=atoi(argv[1]); /* n-1 parce que le main est aussi compté */ for(int i=0;i0) break; } /* dors 1 min */ sleep(5); /* attends le fils */ wait(&status); } Question 4: Même question que 3) mais avec la hiérarchie suivante : P0-+-P1 |-P2 |-... |- |-n-1 `-Pn #include #include #include #include int main(int argc,char *argv[]) { int status; if(argc < 2 ) { printf("Usage : n_proc \n"); exit(0); } int n=atoi(argv[1]); for(int i=0;i0) continue; } /* dors 1 min */ sleep(5); /* attends le(s) fils */ wait(&status); } Question 5: Même question que pour la 3 et la 4 mais en combinant les hiérarchies de la question 3 et 4 de la manière suivante : P0-+-P1-- ... -- Pn-1 -- Pn |-P2 |-... |- |-n-1 `-Pn #include #include #include #include int main(int argc,char *argv[]) { int status_vert; int status_horiz; if(argc < 2 ) { printf("Usage : n_proc \n"); exit(0); } int n=atoi(argv[1]); /* boucle de création de tous les fils direct de P0 */ for(int i=0;i 0, sinon crée une autre lignée */ if(pid==0) { if(i>0) break; else { /* attention : n-1 */ for(int i=0;i0) break; } sleep(60); wait(&status_horiz); exit(0); } } /* père : crée d'autres fils */ if(pid>0) continue; } /* dors 1 min */ sleep(60); /* attends le(s) fils */ wait(&status_vert); } Question 6: Ecrire un programme qui crée un processus fils pour lancer la commande ps -f. Le processus père attendra la fin du processus fils. Analyser le résultat du programme. #include #include #include /* Ecrire un programme qui crée un processus fils pour lancer la commande ps -f. Le processus père attendra la fin du processus fils. Analyser le résultat du programme : ./q6 PID TTY TIME CMD 26427 pts/6 00:00:00 bash 32640 pts/6 00:00:00 q6 32641 pts/6 00:00:00 ps fils de pid 32641 terminé, code de sortie 0, signaled 0 Analyse : ps s'affiche lui-même (selfie haha), il est fils du processus q6. */ int main(int argc,char *argv[]) { int pid; if ( (pid=fork()) < 0 ) perror("fork"); /* fils, lancement de la commande ps -f */ if(pid == 0 ) { execl("/bin/ps", "-f", NULL); perror("execl"); exit(10); } /* père, se mets en attente du fils */ /* crée un nouveau processus dès que fils termine : on boucle*/ if(pid > 0) { int status=-1; if(wait(&status)<0) perror("wait"); printf("fils de pid %d terminé, code de sortie %d, signaled %d\n", pid, WEXITSTATUS(status), WIFSIGNALED(status)); } } Question 7: En utilisant l'aide de l'appel système pipe(), écrire un programme de test qui se communique vers lui même à travers le tube. #include #include #include int main(int argc,char *argv[]) { int pipefd[2]; if ( pipe(pipefd) < 0 ) perror("pipe"); /* on écrit et on lit alternativement dans le pipe */ /* on dort entre deux opération et on affiche le nombre */ /* d'octets lus attention : on envoie 4 octets ASCII "abcd" dans le tube, mais ce n'est pas une chaîne C, elle ne termine pas par un zéro. il faut prévoir le 5ème octet dans le buffer pour l'afficher correctement*/ while(1) { int nb_read; int nb_write; char buffer[5]={0}; if((nb_write=write(pipefd[1],"abcd",4))<0) perror("write"); printf("écrit %d octets dans le tube\n", nb_write); sleep(1); if((nb_read=read(pipefd[0],buffer,4))<0) perror("read"); printf("lu %d octets dans le tube : %s\n", nb_read, buffer); } } Question 8: Ecrire un programme qui crée un tube puis crée ensuite un processus fils (fork()). Le processus fils utilise le tube pour envoyer un message au père, qui le convertit en majuscule et l'affiche sur la sortie standard. Pour convertir un caractère en majuscule, voir la fonction toupper() #include #include #include int main(int argc,char *argv[]) { int pipefd[2]; int pid; if ( pipe(pipefd) < 0 ) perror("pipe"); if ( (pid=fork()) < 0 ) perror("fork"); /* fils, envoie d'un message au père via le tube */ /* ferme l'entrée du tube */ /* ferme la sortie une fois le message envoyé pour provoquer la fin de lecture sur le processus père (retour de read égal à 0)*/ if(pid == 0 ) { if(close(pipefd[0])<0) perror("close"); if(write(pipefd[1],"bonjour", 7)<0) perror("write"); close(pipefd[1]); sleep(20); exit(10); } /* père : convertit le message reçu sur le tube en majuscule et l'affiche sur la sortie standard */ if(pid > 0) { char c; char c_maj; int nb_read; if(close(pipefd[1])<0) perror("close"); while((nb_read=read(pipefd[0],&c, 1))>0) { c_maj=toupper(c); write(1,&c_maj,1 ); } if(nb_read<0) perror("read"); } } Question 9: Ecrire un programme qui crée un tube, puis crée un processus fils. Le processus fils : - utilise le tube pour y envoyer une chaînee de caractère - fait une pause de 10secondes. - Envoie un deuxième message dans le tube Le processus père : - Lit puis affiche tous les messages qui arrivent par le tube Mettre en évidence que l'appel à read() du père est bloquant. Comment pourrait-on utiliser cette propriété pour synchroniser des processus ? Implémenter l'un des mécanismes de synchronisation vus en concurrence avec les tubes (mutex, sémaphore, etc) Question 10: Ecrire un programme qui calcule la somme des carrés avec plusieurs processus communiquants. Exemple : 458^2 + 1234^2 + 999^2. Un processus sera utilisé pour calculer chaque Terme. Le processus fils fait le calcul et l'envoie au père Le père lit tout les résultats et en fait l'addition avant d'afficher le résultat. Votre programme devra fonctionner avec un nombre quelconque de termes donnés en ligne de commande au programme initial. Question 11: En utilisant fork(), execve() pipe() programmer l'équivalent de la commande shell suivante en C : ls /dev | head -n 30 Question 12 : Créer un programme C qui contruit un anneau de communication entre 3 processus via des pipes système. Votre programme devra créer 3 tubes t1, t2, t3 et 3 processus p1, p2 et p3. - Tout ce que p1 envoit dans t1 est lu par p2 depuis t1. - Tout ce que p2 envoit dans t2 est lu par p3 depuis t2. - Touce ce que p3 envoit dans t3 est lu par p1 depuis t3. Le processus p1 enverra un caractère dans t1 et s'attendra à le récupérer dans t3 le plus vite possible. Mesurer le temps nécessaire au caractère pour faire le tour complet de l'anneau. Réfléchir à la manière dont vous procéderiez pour écrire le même programme construisant un anneau de communication entre un nombre n quelconque de processus.