Linux/Unix : Les processus

18 septembre 2013 rdorigny 0 commentaires

La notion de processus est un élément clé dans la programmation en C Système Linux. On les trouve partout, il suffit de lancer la commande pstree ou ps -aef dans une console pour retrouver tous les services associés au numéro de processus.

Nous allons étudier, le clonage grâce à la fameuse fonction fork(), avec quelques d'emplois pour bien comprendre ce concept.



1) Généralités autour des processus

Unix propose des mécanismes de code multi-tache depuis les années 70, on peut dire que cette vision est désormais quasi-obligatoire. Après, ce pose la question processus ou thread, le processus est un clone qui dispose de son propre espace mémoire avec le même code, le thread lui partage l'espace mémoire.

Chaque processus se voit accorder une zone d'espace mémoire virtuelle (voir chapitre précédent). Ceci dit rien n'empêche ensuite dans cette espace dédié de réaliser des Thread. Donc, le processus n'a pas à supporter de concurrence pour sauvegarder sa zone mémoire. Ensuite, le noyau possède un mécanisme d’ordonnancement (scheduling) pour réaliser un partage du temps CPU à chaque processus/thread.

Pour lister les différents processus en cours, vous pouvez lancer la commande ps -aef. La première chose que l'on peut observer, c'est que chaque processus est associé à un numéro de processus, le PID.

Dans son fonctionnement, Linux créé un processus root qui a toujours le numéro 1, ensuite on utilise la fonction fork(), pour le dupliquer et ainsi obtenir un second processus. Les processus sont initialement totalement identiques, sauf qu'il y a processus dit père et un processus dit fils.

Donc, nous avons les fonctions:
  • pid_t fork(void) : duplication de processus,
  • pid_t getpid(void) : cette fonction renvoie le numéro de PID du processus courant,
  • pid_t getpid(void) : cette fonction renvoie le numéro de PPID du processus courant, soit le numéro de PID du père.

  • Donc: Juste après le fork(), les processus sont exactement les même, ils exécutent le même code avec les même données. Comment les différencier? Et bien, en testant le retour du fork(), si le processus reçoit 0, il s'agira du fils, et s'il reçoit le PID du fils, c'est que c'est le père.

    Voici un exemple de code avec deux processus concurrents:
    #include <stdio.h> #include <unistd.h> #include <stdlib.h> #include <sys/types.h> int main(void){ int pid; pid=fork(); if (pid<0){ perror("Echec lors du clonage..."); exit(1); } printf("PID : %d n",pid); if (pid==0) { printf("Affichage via le fils.n"); } else { printf("Affichage via le père.n"); } exit(0); }




    Si vous souhaitez voir les processus, il suffit de faire une boucle sans fin, d'ouvrir une autre console, et taper la commande ps -aef.
    #include <stdio.h> #include <unistd.h> #include <stdlib.h> #include <sys/types.h> int main(void){ int pid; pid=fork(); if (pid<0){ perror("Echec lors du clonage..."); exit(1); } while (1){ if (pid==0) { printf("Affichage via le fils.n"); sleep(5); } else { printf("Affichage via le père.n"); sleep(5); } } exit(0); }

    Ce qui donne:
    On voit que le processus père est 4588 et le fils 4589. Si on tue le père par un kill -9 4588, le processus fils sera adopté par le processus init qui est le numéro 1.

    2) La primitive wait

    La primitive permet de stopper le père est d'attendre que le fils se termine pour continuer sa progression séquentielle. Dans les faits, le processus fils envoie un signal SIGCHLD et se met en zombie jusqu'à ce que le père réceptionne le message.

    Voici un exemple d'utilisation de cette fonction:
    #include <stdio.h> #include <unistd.h> #include <stdlib.h> #include <sys/types.h> int main(void){ pid_t pid,pidfils; int retour; printf("PID du père: %dn",getpid()); switch (pid=fork()) { case -1: perror("Erreur lors du clonage "); break; case 0: //Processus fils printf("PID du fils: %dn",getpid()); sleep(10); exit(33); //Ici c'est le processus père! default: pidfils=wait(&retour); printf("Mort du processus: %dn",pidfils); } exit(0); }

    3) La fonction exec

    Cette fonction remplace le processus courant par un autre en chargeant le programme passé en paramètre. Il y a écrasement en mémoire du code et des données, mais le processus conserve son numéro de PID.

    Il y a une famille de fonction exec*, voyons avec l'exemple ci-dessous.
    #include <stdio.h> #include <unistd.h> #include <stdlib.h> #include <sys/types.h> int main(void){ pid_t pid,pidfils; int retour; system("ps f"); execl("/bin/ps","ps","f",NULL); exit(1); }

    Ce qui donne l'affichage ci-dessous, on observe l'écrasement de la fonction ps initiale.

    Conclusion

    Depuis qu'il y a les threads, le mécanisme des processus est moins utilisé, à tort car à la différence des threads il dispose de son propre espace mémoire, et donc les processus ne nécessitent pas la mise en oeuvre de mécanismes lourds de protection des données (comme les mutex).






    Pseudonyme (obligatoire) :
    Adresse mail (obligatoire) :
    Site web :




    © 2017 www.doritique.fr par Robert DORIGNY