fork

Dupliquer un processus

01/01/2002 10 827 lectures 6 commentaires 4.6/5 (7 votes) Sébastien Sougnez

AreaProg recherche des rédacteurs. Plus d'informations

Comme nous l'avons déjà vu, un processus sous Unix est toujours créé à partir d'un autre, mais comment cela fonctionne ? Eh bien, cela peut se faire grace à un fork. Effectivement, un fork est en fait ce qui permet à un programme de se dupliquer. Il existe alors un lien entre les deux processus, en effet, le processus s'étant dupliqué sera le père (ou parent) du processus dupliqué, qui s'appelera le fils. Presque toute les informations seront transmises du père au fils, sauf les protections sur les fichiers et les signaux en attentes (j'y reviendrai plus tard dans les cours). Sachez cependant qu'il est préférable d'utiliser les threads plutot qu'un fork, car ce dernier dupliquera TOUT le programme, tandis qu'un thread ne dupliquera qu'une partie des informations du processus vu qu'ils s'exécuteront dans le même espace virtuel. L'utilisation de fork est donc plus couteuse et plus lente car il y a plus d'informations à reproduire. Penchons nous maintenant sur le signature de cette fonction :
 

#include <sys/types.h>
#include <unistd.h>

pid_t fork(void);


Comme vous le voyez, cette fonction renverra une variable du type pid_t (ce type est contenu dans le fichier sys/types.h) et ne prend aucun argument. Si la fonction échoue, la valeur renvoyée sera -1, aucun fils ne sera créé et errno contiendra le code de l'erreur. Par contre, si la fonction réussit, la valeur renvoyée sera différente dans le cas du fils et du père. Dans le cas du fils, la fonction fork renverra 0, par contre, dans le cas du père, la fonction renverra le PID du fils. Ce qu'il faut bien comprendre c'est que quand vous faites un fork, l'ordinateur crée réellement un clône de votre programme et étant donné que votre programme est en cours d'exécution lors du fork, le processus fils sera aussi en exécution. Etant donné que le processus fils sera une copie parfaite du processus père, le processus fils s'exécutera à partir de l'instruction suivant l'instruction fork. Vous allez mieux comprendre grace aux 2 applications qui vont suivre.
 

Application 1


Nous allons ici faire un simple programme qui va utiliser fork pour se dupliquer et afficher un message dans le cas ou le processus sera le père ou le fils. Tapez donc :
 

#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>

int main() {

	pid_t pid = fork();

	if (pid == 0) {
		printf ("Je suis le fils !\n");
		scanf ("%*c");
	} else {
		printf ("Je suis le père !\n");
		scanf ("%*c");
	}

	return 0;

}
Image


Donc ici, nous utilisons d'entrée de jeu l'instruction fork et nous plaçons le résultat dans la variable de type pid_t nommée pid. A ce moment là, le processus sera dupliqué et nous nous retrouverons avec deux processus quasiment identiques. Le reste du code sera le même pour les deux processus, mais la variable pid vaudra 0 si le processus est le fils et il vaudra le PID de ce fils si c'est le processus parent. Autrement dit, les processus vont s'exécuter tout les deux en même temps. Dans le cas du père, la valeur de pid sera différente de 0, autrement dit, le if ne sera pas respecté, il exécutera donc les instructions du else qui servent à afficher un message indiquant que le processus est le processus père et nous attendons une réaction de l'utilisateur grâce au scanf. Dans le cas du fils, la valeur pid sera de 0, la condition du if sera donc respectée et le prorgamme affichera donc une phrase indiquant à l'utilisateur que le processus s'exécutant est le processus fils. Si vous exécutez ce programme, vous verrez que les messages apparaissent d'un coup et puis le programme attend deux réactions de l'utilisateur, cela vient du fait que comme les deux processus s'exécutent en même temps, il est impossible de dire quel processus ira "plus vite" que l'autre, cela dépendra du scheduler et du dispatcher de l'ordinateur (le scheduler est l'algorithme servant à décider quel processus sera exécuté et le dispatcher sert à lancer le processus choisit par le scheduler).
 

Application 2


Nous allons maintenant voir une deuxième application permettant de vous montrer que lorsque nous dupliquons un processus, il n'y a que les verrous sur les fichiers et les attentes de signaux (j'y reviendrai plus tard) qui ne sont pas hérités, tout le reste est hérité, je vais vous démontrer ça grace à une variable :
 

#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>

int main() {

	int a = 13;

	pid_t pid = fork();

	if (pid == 0) {
		printf ("Je suis le fils !\nValeur de a : %d\n", a);
		scanf ("%*c");
	} else {
		printf ("Je suis le père !\nValeur de a : %d\n", a);
		scanf ("%*c");
	}

	return 0;

}
Image


Donc ici, nous commençons par déclarer une variable a que nous initialiserons à 13 et ensuite, nous dupliquons le processus. Ici ce sera le même principe que le programme précédent, nous dupliquons le processus, nous regardons la valeur des pid. Si celui-ci vaut 0, nous sommes dans le fils et nous affichons une phrase le signalant mais nous affichons également dans la phrase le contenu de la variable a. Nous faisons pareil si le pid est différent de 0 (dans le cas du père) et comme vous le voyez, que ce soit dans le processus père ou dans le processus fils, la valeur de a est bien de 13. Cela vous montre bien que presque tout est hérité dans le processus fils. Généralement, nous utilisons le fork avec execl. N'oubliez pas de privilégier les threads au fork ;-)

Noter

Veuillez vous identifier ou vous inscrire pour donner une note à cet article.

Commentaires / Questions

Student21 (03/11/2010 - 13:36)

Merci pour cet article, qui m'éclaire pas mal sur le sujet. J'aurais tout de même une question:

Est-il possible de recréer des processus fils à partir d'un processus fils, et que se passera-t-il dans ce cas là.

Quel processus aura pour pid 0?

Bref, merci de m'éclaircir un peu.

yankcaesar (30/09/2012 - 12:56)

Merci, c'est d'une grande utilité .

nana (29/11/2012 - 02:29)

mercii pour ceete article vraiment important , mais svp pour l'exécution de ces programme ils faut qu'on Linux pour executer car j'ai executes ces programmes sur windows (dev c++) mais il affiche un erreur et voila mon programme :
#include <stdlib.h>
#include <sys/types.h>
#include <unistd.h>
#include <stdio.h>

int main(){
int pid;
pid=fork();
if(pid==-1){
printf("Erreue");
}

if(pid==0){
printf("fils");

}
else {
printf("pere ");
}
system("pause");
return EXIT_SUCCESS;
}

Student25 (29/01/2013 - 22:48)

Comment tu ferais pour creer sur base d un processus pere, trois processus fils ???

Zou (05/03/2013 - 23:56)

Merci pour ce bon article ! Je pense qu'il pourrait être bien de le compléter avec les notions de exit et wait =)

Voici comment on crée 3 fils à partir d'un père :

int main(void) {
int pid, i;

for(i=0;i<3;i++) {
pid = fork();
if(pid == 0) printf("je suis le fils numéro %d, de PID=%d", i, pid);
else printf("je suis le père et je viens de créer le fils de PID=%d", pid);
exit(0); // tue le fils pour éviter qu'il crée des petits fils
}
for(i=0;i<3;i++) wait(null); // on attend que tous les fils soient morts
printf("tous les fils sont morts!");
return 0;
}


Un processus fils peut aussi faire un fork() et engendrer des petits fils, par exemple si on enlève le exit(0) ci-dessus, le fils va continuer l'exécution de son programme et va donc lire la boucle. Chaque fils créera donc 2 petits fils et chaque petit fils créera 1 arrière petit fils.

Nes (06/04/2013 - 11:55)

Dans le cas où tu utiliserai un fork sur le fils, celui ci va se dupliquer à son tour, le PID du fils deviendra alors celui du petit fils et celui du petit fils deviendra 0.

Veuillez vous identifier ou vous inscrire pour réagir à cet article.