From c370b85518702643efaa3045e2c477dbe5c7c942 Mon Sep 17 00:00:00 2001 From: Pierre Valarcher Date: Wed, 22 Sep 2021 13:36:31 +0200 Subject: [PATCH] Cours3 --- ASR31-Cours3.md | 289 +++++++++++++++++++++++++++++++++++ Exemples/03-Fork/deuxfils1.c | 28 ++++ Exemples/03-Fork/deuxfils2.c | 41 +++++ Exemples/03-Fork/fork2b.c | 24 +++ Exemples/03-Fork/wait.c | 26 ++++ 5 files changed, 408 insertions(+) create mode 100644 ASR31-Cours3.md create mode 100644 Exemples/03-Fork/deuxfils1.c create mode 100644 Exemples/03-Fork/deuxfils2.c create mode 100644 Exemples/03-Fork/fork2b.c create mode 100644 Exemples/03-Fork/wait.c diff --git a/ASR31-Cours3.md b/ASR31-Cours3.md new file mode 100644 index 0000000..be15b16 --- /dev/null +++ b/ASR31-Cours3.md @@ -0,0 +1,289 @@ +### Quelques exemples + +Soit le programme suivant + +```c +#include +#include +#include +#include + +int main(int argc, char *argv[]) { + + int i, n = 5; + pid_t childpid; + + for (i=0; i permet à un processus père d'attendre jusqu'à ce que le procesuss fils termine. La fonction retourne l'identifiant du processus fils à l'adresse de status + +```c +int waitpid(int pid, int *status, int options); +``` + +> permet à un processus père d'attendre jusqu'à ce que le processus fils de numéro pid termine, il retourne l'identifiant du processus fils et son état de terminaison à l'adresse de status. + +```c +void exit(int return_code); +``` + +> permet de finir volontairement l'exécution du processus et donne son état de terminaison. A noter qu'un processus peut terminer aussi par un arrêt forcé provoqié par un signal envoyé au processus + + +Le processus appelant est mis en attente jusqu’à ce que l’un de ses fils termine. Quand cela se produit, il revient de la fonction. Si ``status`` est différent de 0, alors 16 bits d’information sont rangés dans les 16 bits de poids faible de l’entier pointé par ``status``. Ces informations permettent de savoir comment s’est terminé le processus selon les conventions suivantes : + +- Si le fils est stoppé, les 8 bits de poids fort contiennent le numéro du signal qui a arrêté le processus et les 8 bits de poids faible ont la valeur octale ``0177``. +- Si le fils s’est terminé avec un ```exit()```, les 8 bits de poids faible de ``status`` sont nuls et les 8 bits de poids fort contiennent les 8 bits de poids faible du paramètre utilisé par le processus fils lors de l’appel de ``exit()``. +- Si le fils s’est terminé sur la réception d’un signal, les 8 bits de poids +fort de ``status` sont nuls et les 7 bits de poids faible contiennent le +numéro du signal qui a causé la fin du processus. + +Dans le fichier d'en-tête `````` sont définis différents macros +qui permettent d’analyser la valeur de status afin de determiner la cause de terminaison du processus. En particulier, le processus père peut obtenir la valeur des 8 bits de poids faible du paramètre qui reçoit depuis ```exit()``` de la part du fils en utilisant le macro : +```c +WEXITSTATUS(status) +/* +#define WEXITSTATUS(s) (((s)>>8)&0xFF) +*/ +``` +Si le processus appelant ```wait()``` n'a pas de fils alors la fonction renvoie une erreur. + +#### Exemple 1 + +```c +#include +#include +#include +#include +#include + +int main() { + + pid_t fils_pid ; + + fils_pid = fork (); + + if ( fils_pid == 0) { + printf("Je suis le fils avec pid %d\n",getpid()); exit(3); + } else { + if (fils_pid > 0) { + printf ("Je suis le pere avec pid %d.\n" , getpid ()); + printf("J’attends que mon fils se termine\n"); + wait (NULL) ; + printf("Normalement mon fils en a fini!\n"); + } else { + printf("Erreur dans la creation du fils\n"); + } + } + exit (0); +} +``` + +Dont une exécution est + +```sh +bash-4.4$ ./wait +Je suis le pere avec pid 20892. +J’attends que mon fils se termine +Je suis le fils avec pid 20893 +bash-4.4$ +``` +#### Exemple 2 + +```c +/* fork2b.c */ + + +#include +#include +#include +#include + +int main(int argc, char *argv[]) { + + int i, n = 5; + pid_t childpid; + + for (i=0; i= 0) + ; + + return EXIT_SUCCESS; +} +``` + +Avec une exécution possible : + +```sh +bash-4.4$ ./fork2b +Processus 21041 avec pere 21039, i = 1 +Processus 21040 avec pere 21039, i = 0 +Processus 21042 avec pere 21039, i = 2 +Processus 21044 avec pere 21040, i = 1 +Processus 21043 avec pere 21039, i = 3 +Processus 21045 avec pere 21042, i = 3 +Processus 21046 avec pere 21041, i = 2 +Processus 21047 avec pere 21039, i = 4 +Processus 21048 avec pere 21040, i = 2 +Processus 21049 avec pere 21044, i = 2 +Processus 21050 avec pere 21042, i = 4 +Processus 21051 avec pere 21043, i = 4 +Processus 21052 avec pere 21045, i = 4 +Processus 21053 avec pere 21041, i = 3 +Processus 21054 avec pere 21046, i = 3 +Processus 21055 avec pere 21040, i = 3 +Processus 21056 avec pere 21048, i = 3 +Processus 21057 avec pere 21044, i = 3 +Processus 21058 avec pere 21049, i = 3 +Processus 21059 avec pere 21041, i = 4 +Processus 21061 avec pere 21040, i = 4 +Processus 21060 avec pere 21046, i = 4 +Processus 21063 avec pere 21053, i = 4 +Processus 21062 avec pere 21048, i = 4 +Processus 21065 avec pere 21044, i = 4 +Processus 21064 avec pere 21054, i = 4 +Processus 21066 avec pere 21049, i = 4 +Processus 21067 avec pere 21055, i = 4 +Processus 21069 avec pere 21057, i = 4 +Processus 21070 avec pere 21058, i = 4 +Processus 21068 avec pere 21056, i = 4 +bash-4.4$ +``` + +##### Questions + +1- Quelle est la valeur de retour de ```wait``` si il n'y a pas de fils + +2- Dessiner le graphe quand ```n = 3```, pour ```fork2b.c```. + +3- Ecrire un programme qui nous permet de savoir si ```wait()``` attend un ou tous les procesuss + + +### Exemple 3 + +```c +#include +#include +#include +#include + + +void fils(int i); + +int main() { + int status ; + pid_t pid; + + pid = fork(); + + if (pid == -1) perror("fork"); + else if (pid ==0) // creation du second fils + fils (1) ; + + pid = fork(); + + if (pid == -1) perror("fork"); + else if (pid ==0) // creation du second fils + fils (2) ; + + + if (wait(&status) > 0) + printf("fin du fils %d\n", WEXITSTATUS(status)); + else perror("wait"); + + if (wait(&status) > 0) + printf("fin du fils %d\n", WEXITSTATUS(status)); + else perror("wait"); + + + if (wait(&status) > 0) + printf("fin du fils %d\n", WEXITSTATUS(status)); + else perror("wait"); + + return 0 ; +} + +void fils (int i) { + sleep(2); + exit(i); +} +``` + +##### Questions +1- Analyser le code précédent +2- Depuis le shell on peut envoyer un signal à un processus via ```kill```. Faire un programme C qui affiche le signal qui a été envoyé à un processus créé. + +### Processus zombie + +L’exécution asynchrone entre processus parent et fils a certaines conséquences. Souvent, le fils d’un processus se termine, mais son père ne l’attend pas. Le processus fils devient alors un processus zombie. Le processus fils existe toujours dans la table des proces- sus, mais il n’utilise plus les ressources du *kernel*. + +L’exécution de l’appel système ```wait()``` ou ```waitpid()``` par le processus père élimine le fils de la table des processus. Il peut y avoir aussi des terminaisons prématurées, où le processus parent se termine avant ses processus fils. Dans cette situation, ses processus fils sont adoptés par le processus ```init```, dont le ```pid = 1```. + + +#### Questions + +1- Illustrer les processus zombies + + + + + + + diff --git a/Exemples/03-Fork/deuxfils1.c b/Exemples/03-Fork/deuxfils1.c new file mode 100644 index 0000000..1487a17 --- /dev/null +++ b/Exemples/03-Fork/deuxfils1.c @@ -0,0 +1,28 @@ +#include +#include +#include +#include + + +void fils(int i); + +int main() { + int status ; + if(fork()) // creation du premier fils + { + if(fork()==0) // creation du second fils + fils (2) ; + } + else fils (1) ; + if ( wait(&status) > 0 ) + printf("fin du fils %d\n", status>>8) ; + if (wait(&status)>0) + printf("fin du fils %d\n", status>>8) ; + + return 0 ; +} + +void fils (int i) { + sleep(2); + exit(i); +} \ No newline at end of file diff --git a/Exemples/03-Fork/deuxfils2.c b/Exemples/03-Fork/deuxfils2.c new file mode 100644 index 0000000..04bdc5c --- /dev/null +++ b/Exemples/03-Fork/deuxfils2.c @@ -0,0 +1,41 @@ +#include +#include +#include +#include + + +void fils(int i); + +int main() { + int status ; + pid_t pid; + + pid = fork(); + if (pid == -1) perror("fork"); + else if (pid ==0) // creation du second fils + fils (1) ; + + pid = fork(); + if (pid == -1) perror("fork"); + else if (pid ==0) // creation du second fils + fils (2) ; + + if (wait(&status) > 0) + printf("fin du fils %d\n", WEXITSTATUS(status)); + else perror("wait"); + + if (wait(&status) > 0) + printf("fin du fils %d\n", WEXITSTATUS(status)); + else perror("wait"); + + if (wait(&status) > 0) + printf("fin du fils %d\n", WEXITSTATUS(status)); + else perror("wait"); + + return 0 ; +} + +void fils (int i) { + sleep(2); + exit(i); +} \ No newline at end of file diff --git a/Exemples/03-Fork/fork2b.c b/Exemples/03-Fork/fork2b.c new file mode 100644 index 0000000..d732909 --- /dev/null +++ b/Exemples/03-Fork/fork2b.c @@ -0,0 +1,24 @@ +/* Auteur : */ + + +#include +#include +#include +#include + +int main(int argc, char *argv[]) { + + int i, n = 3; + pid_t childpid; + + for (i=0; i= 0) + ; + + return EXIT_SUCCESS; +} \ No newline at end of file diff --git a/Exemples/03-Fork/wait.c b/Exemples/03-Fork/wait.c new file mode 100644 index 0000000..0aa6cff --- /dev/null +++ b/Exemples/03-Fork/wait.c @@ -0,0 +1,26 @@ +#include +#include +#include +#include +#include + +int main() { + + pid_t fils_pid ; + + fils_pid = fork (); + + if ( fils_pid == 0) { + printf("Je suis le fils avec pid %d\n",getpid()); sleep(1); exit(3); + } else { + if (fils_pid > 0) { + printf ("Je suis le pere avec pid %d.\n" , getpid ()); + printf("J’attends que mon fils se termine\n"); + wait (NULL) ; + printf("Normalement mon fils en a fini!\n"); + } else { + printf("Erreur dans la creation du fils\n"); + } + } + exit (0); +}