fork(2)
Appel système
Duplique le processus qui l'appelle. L'enfant reçoit une copie de la mémoire et des descripteurs ouverts, et la valeur de retour dit qui est qui.
#include <unistd.h>
pid_t fork(void);Description
fork crée un nouveau processus, l'enfant, en copiant celui qui l'appelle, le parent. Au retour de l'appel, les deux exécutent la suite du même programme. L'enfant a son propre PID, et son parent est le processus qui a appelé fork.
La mémoire est copiée : variables, pile, tas, et aussi les tampons de printf qui n'ont pas encore été vidés. Linux ne recopie réellement une page que quand l'un des deux processus la modifie (copie à l'écriture), ce qui rend l'appel rapide. Les descripteurs de fichiers sont dupliqués eux aussi, mais chacun désigne le même fichier ouvert que dans le parent, avec la même position de lecture ou d'écriture : c'est ce qui permet à un parent et un enfant de partager un pipe.
Valeur de retour
fork renvoie deux fois, une fois dans chaque processus :
| Valeur | Dans quel processus |
|---|---|
0 | l'enfant |
| le PID de l'enfant, positif | le parent |
-1 | le parent seul, aucun enfant n'a été créé et errno dit pourquoi |
Les causes d'échec classiques sont EAGAIN (limite du nombre de processus atteinte) et ENOMEM (mémoire du noyau insuffisante).
Pièges
Rien ne garantit qui, du parent ou de l'enfant, s'exécute en premier. Un programme qui compte sur un ordre doit se synchroniser, avec
waitpidou un pipe.Un
printfappelé avantforkpeut s'afficher deux fois quand la sortie va dans un pipe ou un fichier : le tampon non vidé est copié dans l'enfant. Appellefflush(stdout)juste avantfork.Un enfant terminé reste à l'état de zombie tant que le parent ne l'a pas attendu avec
waitouwaitpid.Dans une boucle, oublier de sortir de l'enfant (avec
exitou unreturn) fait que l'enfant continue la boucle et crée à son tour des processus.
Exemple
#include <stdio.h>#include <sys/wait.h>#include <unistd.h>
int main(void){ int x = 1; pid_t pid = fork();
if (pid == -1) { perror("fork"); return 1; } if (pid == 0) { x = 42; printf("enfant : x = %d\n", x); return 0; } waitpid(pid, NULL, 0); printf("parent : x = %d\n", x); return 0;}$ gcc -Wall -Wextra copie.c -o copie$ ./copieenfant : x = 42parent : x = 1L'enfant modifie sa copie de x, celle du parent n'a pas bougé. Le parent attend l'enfant avant d'afficher, ce qui fixe l'ordre des deux lignes.
process_stream_open
Écris process_stream_open, qui crée un enfant avec fork pour lancer une commande via execvp et rend au parent une extrémité du pipe, sans attendre l'enfant.