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.

Synopsis
#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 :

ValeurDans quel processus
0l'enfant
le PID de l'enfant, positifle parent
-1le 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 waitpid ou un pipe.

  • Un printf appelé avant fork peut s'afficher deux fois quand la sortie va dans un pipe ou un fichier : le tampon non vidé est copié dans l'enfant. Appelle fflush(stdout) juste avant fork.

  • Un enfant terminé reste à l'état de zombie tant que le parent ne l'a pas attendu avec wait ou waitpid.

  • Dans une boucle, oublier de sortir de l'enfant (avec exit ou un return) fait que l'enfant continue la boucle et crée à son tour des processus.

Exemple

copie.c
#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;}
Terminal
$ gcc -Wall -Wextra copie.c -o copie$ ./copieenfant : x = 42parent : x = 1

L'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.

C

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.

Ouvrir l'exercice

À toi d'écrire le code.