IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

C Discussion :

Utilisation de fork()


Sujet :

C

  1. #1
    Membre confirmé
    Homme Profil pro
    .
    Inscrit en
    Octobre 2018
    Messages
    62
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 26
    Localisation : France, Seine et Marne (Île de France)

    Informations professionnelles :
    Activité : .

    Informations forums :
    Inscription : Octobre 2018
    Messages : 62
    Par défaut Utilisation de fork()
    Bonjour

    Je suis actuellement un cours sur la programmation Système, plus particulièrement sur le chapitre des processus.
    On a abordé le principe de la fonction fork() qui va créer un nouveau processus. Mais je ne comprends pas réellement ce qu'il se passe avec le code. Par exemple, dans ce genre de code :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    void main(int argc, char** argv ){
      pid_t pid_fils;
      pid_fils = fork();
      if(pid_fils == 0){
        execlp("/bin/sh","sh", "-c",argv[1],NULL);
      }else{
        wait(NULL);
      }
    }
    De ce que j'ai compris, le fils va donc uniquement lire la partie du code où le pid_fils == 0. Mais je ne comprends pas réellement comme ça fonctionne.
    Pourriez vous me donner une explication plus précise ?
    Merci d'avance,

    Ben

  2. #2
    Expert éminent
    Avatar de Médinoc
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Septembre 2005
    Messages
    27 391
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 41
    Localisation : France

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Septembre 2005
    Messages : 27 391
    Par défaut
    Pour expliquer ça, on peut partir de la signification du mot fork: Une fourche, comme sur la route. Une route qui se sépare en deux.
    Voilà ce que fait fork(): Il sépare ton processus en deux processus identiques, à une différence près:
    Il y a un lien de parenté entre les deux processus: L'un est le père et l'autre le fils, et l'OS n'aime pas que le processus père se termine avant le processus fils.

    Ce qui est important à comprendre, c'est que lorsque fork() sépare le processus en deux, les deux processus résultats sont tous les deux au même point d'exécution: Ils sont tous les deux dans la fonction fork() qui n'a pas encore retournée. C'est un concept complètement différent de la création de processus telle qu'elle existe sous Windows, où un nouveau processus commence forcément du début.

    La différence entre père et fils se manifeste de deux façons:
    1. Chacun a son propre identificateur de processus (PID): Le père a le même PID qu'avant l'appel à fork(), alors que le processus fils a reçu un nouveau PID.
    2. La valeur de retour de la fonction fork() diffère entre les deux: Dans le processus père, fork() va retourner le PID du processus fils; dans le processus fils, fork() va retourner zéro.

    C'est comme ça que le processus fils exécutera uniquement le code dans le if(pid_fils==0), et le processus père exécutera uniquement le code du else.
    SVP, pas de questions techniques par MP. Surtout si je ne vous ai jamais parlé avant.

    "Aw, come on, who would be so stupid as to insert a cast to make an error go away without actually fixing the error?"
    Apparently everyone.
    -- Raymond Chen.
    Traduction obligatoire: "Oh, voyons, qui serait assez stupide pour mettre un cast pour faire disparaitre un message d'erreur sans vraiment corriger l'erreur?" - Apparemment, tout le monde. -- Raymond Chen.

  3. #3
    Membre prolifique
    Avatar de Sve@r
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Février 2006
    Messages
    12 800
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Oise (Picardie)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : Février 2006
    Messages : 12 800
    Billets dans le blog
    1
    Par défaut
    Bonjour
    Citation Envoyé par LePtitBen Voir le message
    De ce que j'ai compris, le fils va donc uniquement lire la partie du code où le pid_fils == 0. Mais je ne comprends pas réellement comme ça fonctionne.
    Imagine le code suivant
    Code c : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    int main() {
    	printf("Hello\n");
    }
    Si tu l'exécutes, tu auras une ligne affichée à l'écran. C'est parce que l'exécution de ce code est dévolue à un processus qui se charge d'exécuter ses instructions.

    Maintenant, une toute petite modification
    Code c : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    int main() {
    	fork();
    	printf("Hello\n");
    }
    Au moment où le fork() s'exécute, il génère un second processus copie (et aussi appelé "fils") du premier. A partir de là donc, tout ce qui se situe en dessous sera traité (et exécuté) par deux processus tournant en parallèles. Et donc tu auras 2 affichage à l'écran car chaque processus affichera "Hello".

    Jusque là c'est pas très intéressant d'avoir deux programmes faisant la même chose. Ce qui est intéressant, c'est de pouvoir distinguer qui est qui pour pouvoir leur faire faire des trucs distincts voire en collaboration.
    Et le moyen de distinguer qui est qui se fait par le retour de la fonction fork(). Dans la branche fils elle retourne 0 et dans la branche père elle retourne le n° de pid du fils généré.

    Tu peux, pour mieux distinguer les procesuss, modifier un peu le code
    Code c : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    int main() {
    	fork();
    	printf("Hello %d, %d\n", getppid(), getpid());
    }
    Là, on affiche le n° du processus père et celui du courant. Dans un des deux affichages tu auras (par exemple) 8700, 8701 et dans l'autre tu auras 8701, 8702 (parce que le ppid de l'un est aussi le pid de l'autre).


    Citation Envoyé par Médinoc Voir le message
    et l'OS n'aime pas que le processus père se termine avant le processus fils.
    Pas d'accord. L'OS sait parfaitement gérer et dans ce cas, le processus devenu orphelin est alors rattaché à init, premier processus et père de tous les autres.
    Mon Tutoriel sur la programmation «Python»
    Mon Tutoriel sur la programmation «Shell»
    Sinon il y en a pleins d'autres. N'oubliez pas non plus les différentes faq disponibles sur ce site
    Et on poste ses codes entre balises [code] et [/code]

  4. #4
    Responsable Systèmes


    Homme Profil pro
    Gestion de parcs informatique
    Inscrit en
    Août 2011
    Messages
    18 160
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Gestion de parcs informatique
    Secteur : High Tech - Matériel informatique

    Informations forums :
    Inscription : Août 2011
    Messages : 18 160
    Par défaut
    Je rajouterais qu'une fois le processus fils créée, la fonction suivante est appelée :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    execlp("/bin/sh","sh", "-c",argv[1],NULL);
    Les fonctions de la famille exec chargent le programme en paramètre (/bin/sh dans ce cas) dans l'espace mémoire du processus appelant en écrasant donc le code courant. fork suivi de exec est la méthode utilisé pour lancer un programme sous Linux. Les fonctions exec ne retournent pas.

    fork va utiliser le système du copy-on-write. Tant qu'il n'y a pas d'écriture, les 2 processus vont utiliser les mêmes zones mémoire, dès qu'il y a une écriture, la zone mémoire concernée est dupliquée et l'espace mémoire du processus concerné mis à jour en conséquence.
    Ma page sur developpez.com : http://chrtophe.developpez.com/ (avec mes articles)
    Mon article sur le P2V, mon article sur le cloud
    Consultez nos FAQ : Windows, Linux, Virtualisation

  5. #5
    Membre confirmé
    Homme Profil pro
    .
    Inscrit en
    Octobre 2018
    Messages
    62
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 26
    Localisation : France, Seine et Marne (Île de France)

    Informations professionnelles :
    Activité : .

    Informations forums :
    Inscription : Octobre 2018
    Messages : 62
    Par défaut
    D'accord, j'ai bien mieux compris ! Merci beaucoup !

  6. #6
    Membre confirmé
    Homme Profil pro
    .
    Inscrit en
    Octobre 2018
    Messages
    62
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 26
    Localisation : France, Seine et Marne (Île de France)

    Informations professionnelles :
    Activité : .

    Informations forums :
    Inscription : Octobre 2018
    Messages : 62
    Par défaut
    Après réflexions, j'ai quand même quelques questions.

    Si je fais :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    void main(){
      if(fork()==0){
        Blabla}
      if(fork()==0){
        Blabla}
      wait(NULL;)
    }
    Ici, je fais deux processus fils. Mais si le premier processus fils commence au premier fork. Il va donc lui aussi faire un fils avec le deuxième fork dans la boucle non ? J'aurais donc au total 3 processus fils non ?

  7. #7
    Membre prolifique
    Avatar de Sve@r
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Février 2006
    Messages
    12 800
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Oise (Picardie)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : Février 2006
    Messages : 12 800
    Billets dans le blog
    1
    Par défaut
    Citation Envoyé par LePtitBen Voir le message
    Il va donc lui aussi faire un fils avec le deuxième fork dans la boucle non ?
    Quelle boucle ? La boucle "if" ou la boucle "main" ???

    Citation Envoyé par LePtitBen Voir le message
    J'aurais donc au total 3 processus fils non ?
    Tu en auras tellement 3 qu'ils sembleront même être 4 si tu réfléchis bien.

    PS: main() n'est pas void (voir mes exemples)
    Mon Tutoriel sur la programmation «Python»
    Mon Tutoriel sur la programmation «Shell»
    Sinon il y en a pleins d'autres. N'oubliez pas non plus les différentes faq disponibles sur ce site
    Et on poste ses codes entre balises [code] et [/code]

  8. #8
    Membre confirmé
    Homme Profil pro
    .
    Inscrit en
    Octobre 2018
    Messages
    62
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 26
    Localisation : France, Seine et Marne (Île de France)

    Informations professionnelles :
    Activité : .

    Informations forums :
    Inscription : Octobre 2018
    Messages : 62
    Par défaut
    Ba. Le premier fork() va exécuter tout ce qu'il y a en dessous du fork en terme de code si j'ai bien compris. Il va donc aussi créer un fils lui aussi avec le deuxième fork() dans le deuxième if, non ? ( Vu qu'il exécute tout ce qu'il y a après le fork). Donc au total, j'ai mon processus principal, mon premier fils qui en a fait un deuxième (donc le troisième) et un quatrième dans le dernier if qui va être créer par le père via le deuxième if. C'est ça ? Ou le fait de mettre le fork dans le if empêche à un premier processus fils d'accéder au deuxième if(fork()==0) ?

  9. #9
    Membre prolifique
    Avatar de Sve@r
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Février 2006
    Messages
    12 800
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Oise (Picardie)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : Février 2006
    Messages : 12 800
    Billets dans le blog
    1
    Par défaut
    Citation Envoyé par LePtitBen Voir le message
    Le premier fork() va exécuter tout ce qu'il y a en dessous du fork en terme de code si j'ai bien compris.
    Absolument. Ainsi je l'ai écrit, ainsi cela se passera.

    Citation Envoyé par LePtitBen Voir le message
    Il va donc aussi créer un fils lui aussi avec le deuxième fork() dans le deuxième if, non ? ( Vu qu'il exécute tout ce qu'il y a après le fork).
    Absolument (bis)

    Citation Envoyé par LePtitBen Voir le message
    Donc au total, j'ai mon processus principal, mon premier fils qui en a fait un deuxième (donc le troisième) et un quatrième dans le dernier if qui va être créer par le père via le deuxième if. C'est ça ?
    Exact. Donc ça fait bien 4 et non 3 comme tu avais dit tout à l'heure.

    Citation Envoyé par LePtitBen Voir le message
    Ou le fait de mettre le fork dans le if empêche à un premier processus fils d'accéder au deuxième if(fork()==0) ?
    Que nenni. Absolument tout le code situé sous le fork() est exécuté. Certains croient (à tort) que puisqu'ils ont isolé le fils ils sont tranquilles et que dans un code de ce genre...
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    int main() {
    	if (fork() == 0) {
    		blabla;
    	}
    	printf("Hello\n");
    }
    Le "Hello" ne se fera que dans le père puisque (selon eux) le cas "fils" a été traité. Et ben non. Certes le cas "fils" fait l'objet d'un traitement "en plus" mais tout ce qui n'est pas isolé dans le cas "père" est alors traité par les deux.

    Seule solution pour écrire un truc de ce genre: faire mourir le fils quand il a fini
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    int main() {
    	if (fork() == 0) {
    		blabla;
    		exit(0);
    	}
    	printf("Hello\n");
    }
    Là c'est bon. Sinon, il faut alors partir dans un code de ce genre
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    int main() {
    	if (fork() == 0) {
    		blabla;
    	}
    	else {
    		printf("Hello\n");
    	}
    	// Et ne rien écrire entre cette accolade et la fin du main()
    }
    Et comme on est généralement attentifs aux posibilités/impossibilités de générer un fils, le code complet est généralement un code écrit sous cette forme
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    int main() {
    	switch (fork()) {
    		case -1: // Erreur de fork()
    			blabla... (gestion de l'erreur)
    			break;
    		case 0: // Fils
    			blabla... (gestion du fils)
    			break;
    		default: // Père
    			printf("Hello\n");
    	}
    	// Et ne rien écrire entre cette accolade et la fin du main()
    }
    Et sinon euh... t'as pas répondu à ma question pour m'aider à identifier la boucle dont tu parlais...
    Mon Tutoriel sur la programmation «Python»
    Mon Tutoriel sur la programmation «Shell»
    Sinon il y en a pleins d'autres. N'oubliez pas non plus les différentes faq disponibles sur ce site
    Et on poste ses codes entre balises [code] et [/code]

  10. #10
    Membre confirmé
    Homme Profil pro
    .
    Inscrit en
    Octobre 2018
    Messages
    62
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 26
    Localisation : France, Seine et Marne (Île de France)

    Informations professionnelles :
    Activité : .

    Informations forums :
    Inscription : Octobre 2018
    Messages : 62
    Par défaut
    Ok ! Merci de ta réponse ! Et je parlais de la deuxième boucle if, mais tu y as répondu.
    Mais du coup, dans ce que j'ai écris, j'ai 2 fils qui vont faire la même chose non ? Ils vont tous les deux exécuter la deuxième boucle if non ?

  11. #11
    Membre prolifique
    Avatar de Sve@r
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Février 2006
    Messages
    12 800
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Oise (Picardie)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : Février 2006
    Messages : 12 800
    Billets dans le blog
    1
    Par défaut
    Citation Envoyé par LePtitBen Voir le message
    Et je parlais de la deuxième boucle if,
    Punaise... c'est vrai que vaut mieux lire ça que d'être aveugle... mais à peine. Sais-tu que tu es en très bonne position pour être le grand gagnant de ce forum ? Réfléchis-tu parfois au sens des mots que tu emploies ???

    Citation Envoyé par LePtitBen Voir le message
    Mais du coup, dans ce que j'ai écris, j'ai 2 fils qui vont faire la même chose non ? Ils vont tous les deux exécuter la deuxième boucle if non ?
    "if" n'est pas une boucle !!!

    Mais sinon effectivement chaque fork() exécute deux fois de façon identique tout ce qui est en dessous.
    Mon Tutoriel sur la programmation «Python»
    Mon Tutoriel sur la programmation «Shell»
    Sinon il y en a pleins d'autres. N'oubliez pas non plus les différentes faq disponibles sur ce site
    Et on poste ses codes entre balises [code] et [/code]

  12. #12
    Membre confirmé
    Homme Profil pro
    .
    Inscrit en
    Octobre 2018
    Messages
    62
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 26
    Localisation : France, Seine et Marne (Île de France)

    Informations professionnelles :
    Activité : .

    Informations forums :
    Inscription : Octobre 2018
    Messages : 62
    Par défaut
    Je prends note de ta remarque !
    On m'a encouragé à mettre un wait(NULL) dans mon main lorsque je fais à chaque fois un fork(). Est-ce que cela peut influencer le comportement de ses fils ? Car la seule chose que j'ai pu comprendre en lisant la doc, c'est que le père attend simplement que le fils fini avant de continuer, c'est bien cela ?

  13. #13
    Responsable Systèmes


    Homme Profil pro
    Gestion de parcs informatique
    Inscrit en
    Août 2011
    Messages
    18 160
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Gestion de parcs informatique
    Secteur : High Tech - Matériel informatique

    Informations forums :
    Inscription : Août 2011
    Messages : 18 160
    Par défaut
    wait suspend un processus en appelant un autre jusqu'à que l'un de ses fils se termine. Ça influence donc le père mais pas les fils.
    Ma page sur developpez.com : http://chrtophe.developpez.com/ (avec mes articles)
    Mon article sur le P2V, mon article sur le cloud
    Consultez nos FAQ : Windows, Linux, Virtualisation

  14. #14
    Membre prolifique
    Avatar de Sve@r
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Février 2006
    Messages
    12 800
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Oise (Picardie)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : Février 2006
    Messages : 12 800
    Billets dans le blog
    1
    Par défaut
    Citation Envoyé par LePtitBen Voir le message
    Car la seule chose que j'ai pu comprendre en lisant la doc, c'est que le père atteint simplement que le fils fini avant de continuer, c'est bien cela ?
    Exact. Donc pas d'influence sur les fils. Ca permet juste de synchroniser le truc pour être plus propre (le père lance un fils puis il attend la fin de son fils avant de se terminer).
    Mon Tutoriel sur la programmation «Python»
    Mon Tutoriel sur la programmation «Shell»
    Sinon il y en a pleins d'autres. N'oubliez pas non plus les différentes faq disponibles sur ce site
    Et on poste ses codes entre balises [code] et [/code]

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. Exemple d'utilisation des fork
    Par fearyourself dans le forum Télécharger
    Réponses: 1
    Dernier message: 29/12/2013, 01h07
  2. utilisations des fork
    Par hamizou87 dans le forum Shell et commandes GNU
    Réponses: 1
    Dernier message: 05/01/2010, 14h02
  3. Utilisation des fork et des pipes
    Par akrogames dans le forum Réseau
    Réponses: 7
    Dernier message: 22/10/2009, 19h22
  4. De la non utilisation du fork
    Par Sékiltoyai dans le forum Réseau
    Réponses: 21
    Dernier message: 22/04/2008, 16h15
  5. Utilisation de tubes dans des fork
    Par je®ome dans le forum Linux
    Réponses: 4
    Dernier message: 31/05/2006, 21h50

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo