02-tp1-fork-exec-correction.pdf
TRANSCRIPT
CORRECTION
CORRECTION
TP1 : fork, exec et signauxRS : Reseaux et Systemes
Deuxieme annee
F Exercice 1. Appel systeme fork.
. Question 1. Ecrire un programme qui cree 10 processus fils. Chacun d’entre eux devra afficher dixfois d’affile son numero d’ordre entre 0 et 9. Verifiez que votre programme affiche 100 caracteres.
Reponse
1 #include <stdio.h>23 int main() {4 int i, j;56 for (i=0; i < 10; i++) {7 switch (fork()) {8 case -1: fprintf(stderr, "Erreur dans %d\n", getpid());9 exit(1);
1011 case 0: /* On est dans un fils */12 for (j = 0; j < 10; j++) {13 printf("%d",i);14 }15 /* Ne pas oublier de sortir sinon on cree fact(10) processus */16 exit(0);1718 default: /* On est dans le pere; ne rien faire */ ;19 }20 }21 exit(0);22 }
Fin reponse
. Question 2. Reprise de la Question 4 du TD1On considere les deux structures de filiation (chaıne et arbre) representees ci-apres. Ecrire un programmequi realise une chaıne de n processus, ou n est passe en parametre de l’execution de la commande (parexemple, n = 3 sur la figure ci-dessus). Faire imprimer le numero de chaque processus et celui de sonpere. Meme question avec la structure en arbre.
exit
exit
exit
exit
exit
pid,
ppid
pid,
ppid
pid,
ppid
pid,
ppid
pid,
ppid
pid,
ppid
exit
pid,
ppid
exit
pid,
ppid
exit
Reponse
1 #include <stdlib.h> /* exit, atoi */2 #include <stdio.h> /* printf */3 #include <unistd.h> /* getpid, fork */4 #include <wait.h> /* wait */56 void arbre(int n) {7 int i;8 printf("Lance %d processus en arbre\n\n",n);9 printf("proc %d fils de %d (shell)\n",getpid(),getppid());
10 for (i=0; i<n; i++) {11 if (fork() == 0) { /* fils */12 printf("proc %d fils de %d\n",getpid(),getppid());13 } else {14 wait(NULL);15 exit(0);16 }17 }18 }1920 void chaine(int n) {21 int i;22 printf("Lance %d processus en chaine\n\n",n);23 printf("proc %d fils de %d (shell)\n",getpid(),getppid());2425 for (i=0; i<n; i++) {26 if (fork() == 0) { /* fils */27 printf("proc %d fils de %d\n",getpid(),getppid());28 exit(0);29 }30 }3132 for (i=0; i<n; i++)
TP1 : fork, exec et signaux
CORRECTION
CORRECTION
33 wait(NULL);34 }3536 int main(int argc, char *argv[ ]) {37 if (argc<2) {38 printf("Usage:\n%s 1 <n> pour lancer <n> processus en arbre\n%s 2 <n> pour lancer <n> processus en chaine\n",39 argv[0], argv[0]);40 exit(1);41 }42 switch(atoi(argv[1])) {43 case 1: arbre(atoi(argv[2])); break;44 case 2: chaine(atoi(argv[2])); break;45 }46 return 0;47 }
Fin reponse
F Exercice 2. Appel systeme exec.
. Question 1. Reprise de la Question 8 du TD1 Ecrire un programme doit qui execute une commandeUnix que l’on lui passe en parametre. Exemple :
1 doit ls -lt /
Reponse
Reponse utilisant argv en place :
1 #include <unistd.h>2 #include <stdio.h>34 int main(int argc,char *argv[ ]) {56 if (argc < 2) {7 fprintf(stderr,"Necessite au moins un argument\n");8 exit(1);9 }
1011 execvp(argv[1],&argv[1]);12 return 0;13 }
Fin reponse
. Question 2. Ecrire un programme multido qui execute au plus cinq fois (dans des processus separes)une commande Unix que l’on lui passe en parametre. Si l’une des executions provoque une erreur, il nefaut pas realiser les executions suivantes.
Reponse
1 #include <stdio.h>2 #include <errno.h>3 #include <wait.h>45 int main(int argc,char *argv[]) {6 int i;7 int status;89 if (argc < 2) {
10 printf("Necessite au moins un argument\n");11 exit(1);12 }13 for (i=0; i<5; i++) {14 switch (fork()) {15 case -1:16 perror("pb de fork");17 exit(1);18 case 0:19 execvp(argv[1],&argv[1]);2021 default:22 if (waitpid(-1, &status, 0) > 0) {23 if (WIFEXITED(status) != 0 && WEXITSTATUS(status) != 0) {24 printf("Child returned an error (code:%d). Balling out\n",25 WEXITSTATUS(status));26 exit(1);27 }28 }29 }30 }31 return 0;3233 }
Exemple de programme qui plante (pour tester) :
2
TP1 : fork, exec et signaux
CORRECTION
CORRECTION
– La premiere fois : cd titi– La deuxieme fois : mkdir toto
Fin reponse
F Exercice 3. Signaux. Rappel : nous utilisons cette annee l’interface POSIX des signaux.
. Question 1. Ecrire un programme ne se terminant qu’au cinquieme Ctrl-C.
Reponse
1 #include <signal.h>2 #include <stdio.h>34 void Recuperation(int sig) {5 static compt = 0;67 if (++compt == 5) {8 printf("J’en ai assez!!\n");9 exit(0);
10 } else {11 printf("OK je recupere le signal SIGINT\n");12 }13 }1415 int main() {16 struct sigaction nvt, old;17 memset(&nvt,0,sizeof(nvt)); /* memset necessaire pour flags=0 */1819 nvt.sa_handler = Recuperation;2021 sigaction(SIGINT, &nvt, &old);2223 printf("Taper 5 ^C pour arreter le programme\n");24 while(1);25 }26
Fin reponse
. Question 2. Ecrire un programme creant deux fils, en envoyant le signal SIGUSR1 a son fils cadet.A la reception de ce signal, le fils cadet devra envoyer le signal SIGUSR2 au fils aine (qui provoque saterminaison) avant de s’arreter.Indication : il est tres difficile d’interchanger les roles des deux fils.
Reponse
1 #include <signal.h>23 int aine, cadet;45 void cadet_sigusr1() {6 printf("Reception du signal SIGUSR1 dans %d\n", getpid());7 kill(aine, SIGUSR2);8 exit(0);9 }
1011 void aine_sigusr2() {12 printf("Reception du signal SIGUSR2 dans %d\n", getpid());13 exit(0);14 }1516 int main(int argc, char **argv) {17 /* Lancer le fils aine */18 if ((aine=fork()) == 0) {19 /* fils */20 struct sigaction nvt, old;21 memset(&nvt,0,sizeof(nvt));22 nvt.sa_handler = aine_sigusr2;23 sigaction(SIGUSR2, &nvt, &old);2425 pause();26 }2728 /* Lancer le fils cadet */29 if ((cadet=fork()) == 0) {30 struct sigaction nvt, old;31 memset(&nvt,0,sizeof(nvt));32 nvt.sa_handler = cadet_sigusr1;33 sigaction(SIGUSR1, &nvt, &old);3435 pause();36 }3738 /* On est dans le pere */39 sleep(1); /* pour etre sur que les signaux sont bien detournes */40 printf("Aine=%d Cadet=%d\n", aine, cadet);41 kill(cadet, SIGUSR1);42 sleep(2); /* pour attendre les affichages */43 return 0;44 }
3
TP1 : fork, exec et signaux
CORRECTION
CORRECTION
Fin reponse
F Exercice 4. Reimplementer if.
. Question 1. Ecrire une version simplifiee du programme if que vous nommerez si.Testez votre travail avec la commande suivante : ./si test -e toto alors echo present sinon echo absent
Reponse
si.c1 #include <stdlib.h>2 #include <stdio.h>3 #include <string.h>4 #include <unistd.h>5 #include <sys/wait.h>67 int main(int argc, char **argv) {8 int alors_pos = 0;9 int sinon_pos = 0;
10 int i = 0;11 int status;1213 while(argv[++i]!=NULL)14 if (!strcmp(argv[i],"alors"))15 alors_pos = i;16 else if(!strcmp(argv[i],"sinon"))17 sinon_pos = i;1819 argv[alors_pos] = NULL;2021 if (sinon_pos)22 argv[sinon_pos] = NULL;2324 if(!(alors_pos)) {25 printf("Syntaxe : ./si expr alors expr [sinon expr]\n");26 return -1;27 }2829 if(fork()==0) {30 execvp(argv[1],&argv[1]);31 perror("execvp casse !");32 return -1;33 }3435 wait(&status);3637 if(WIFEXITED(status)) {38 if(!WEXITSTATUS(status)) {39 if(!sinon_pos)40 sinon_pos=argc;4142 execvp(argv[alors_pos+1],&argv[alors_pos+1]);4344 perror("execvp casse !");45 return -1;4647 } else if(sinon_pos) {4849 execvp(argv[sinon_pos+1],&argv[sinon_pos+1]);5051 perror("execvp casse !");52 return -1;53 }54 // test "si" faux, pas de "sinon"55 return 0;5657 } else {58 // test "si" pas sorti par exit59 return -1;60 }61 }62
Fin reponse
4