Skip to content

Programmation Système - Fork⚓︎


Rappels : Programme vs. Processus⚓︎

important

  • Programme : entité statique, une suite d'instructions compilées
  • Processus : entité dynamique, possède un PID, c'est l'éxecution d'un programme. Possède un contexte propre.

Création d'un Processus⚓︎

Règle d'Or : tout processus UNIX peut créer un ou plusieurs processus.

Donc pour créer un processus nouveau, il en faut déjà un exustant ... qui va être cloné, puis spécialisé.
Il y a donc une filiation entre les processus !

filiation

Primitives⚓︎

PID Courant⚓︎

1
pid_t getpid(void);

Retourne le pid du processus courant (appelant)

PID du Père⚓︎

1
pid_t getppid(void);

Retourne le pid du père du processus courant (appelant)

Tip

Le pendant en Shell serait la commande : ps 😉

Suspension⚓︎

1
2
int sleep (int nb_sec);
int usleep (int nb_msec);

sleep endort le processus jusqu'à ce que nb_sec secondes se soient écoulées, ou jusqu'à ce qu'un signal non-ignoré soit reçu.

usleep endort le processus jusqu'à ce que nb_msec micro-secondes se soient écoulées, ou jusqu'à ce qu'un signal non-ignoré soit reçu.

Renvoient zéro si le temps prévu s'est écoulé, ou le nombre de secondes (micro-secondes) restantes si un signal a réveillé le processus.

Création de processus⚓︎

1
pid_t fork(void);

Permet la création dynamique d’un nouveau processus (fils). par duplication du processus courant (père).

Le processus fils ne diffère du processus père que par les pid et ppid.

Les 2 processus (père et fils) s’exécutent de manière concurrente !

Tip

Bibliothèques :

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

Retourne un entier :

  1. En cas de succès:

    • 0 dans le fils
      • pid du fils dans le père
  2. En cas d’échec

    • -1 dans le père
      • le fils n’est pas créé

Très Important !

La valeur retournée par fork permet donc de faire la distinction entre le père et le fils !

progfork


Exemple basique⚓︎

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
int main(void)
{
    pid_t pid;
    pid = fork();

    if (pid == 0)
        printf(" Je suis le FILS ");
    else
        printf(" Je suis le PERE ");

    return 0;
}

Après fork :

  • allocation d’une entée dans la table des processus au nouveau processus
  • allocation d ’un pid au nouveau processus
  • duplication du contexte du processus père (données, pile…)
  • retour du pid du processus fils à son père et 0 au processus fils

Affichons les PID respectifs :

Dans le ==père== (PID supposé : 1234) : Dans le ==fils== (PID supposé : 2345):
int main(void)
{
    pid_t pid;
    pid = fork();

    if (pid == 0)
    {
        printf(" Je suis le fils");
        printf(" mon pid est = %d ",getpid());
    } else {
        printf(" Je suis le pere ");
        printf(" mon pid est = %d ",getpid());
    }
}
int main(void)
{
    pid_t pid;
    pid = fork();

    if (pid == 0)
    {
        printf(" Je suis le fils");
        printf(" mon pid est = %d ",getpid());
    } else {
        printf(" Je suis le pere ");
        printf(" mon pid est = %d ",getpid());
    }
}

Affichages :

1
2
Je suis le pere mon pid est = 1234
Je suis le fils mon pid est = 2345

PID différents: 1234 et 2345
Les 2 processus exécute le même programme !

On ne peut pas prédire l'ordre des printf !!


Synchronisation⚓︎

Primitives⚓︎

Exit⚓︎

1
void exit(int status);

Exit :

– termine le processus appelant.
– transmet la valeur de status (le mot d’état) au processus père
– ferme les descripteurs de fichiers ouverts
– un signal SIGCHLD est envoyé au processus père.

Wait⚓︎

1
pid_t wait(int *status);

Wait :

attend la terminaison ou l'arrêt d'un processus fils (fils quelconque).
– retourne le PID d'un processus terminé, -1 en cas d’erreur (si tous sont déjà terminés).
stocke la valeur transmise par le fils (exit) dans l'entier pointé par status.

Warning

Le status est codé sur le 2ème octet de l'int pointé :

status

progwait


Exemple complet⚓︎

Dans le ==père== (PID supposé : 1234) : Dans le ==fils== (PID supposé : 2345):
int main(void)
{
    int pid, status;
    pid = fork();

    if (pid == 0) {
        printf(" Je suis le fils");
        exit(3);
    } else {
        printf(" Je suis le pere ");
        printf(" j ’attends la fin de mon fils);
        wait(&status);
        printf("  status = %d ",status>>8);
    }
  return 0;
}
int main(void)
{
    int pid, status;
    pid = fork();

    if (pid == 0) {
        printf(" Je suis le fils");
        exit(3);
    } else {
        printf(" Je suis le pere ");
        printf(" j ’attends la fin de mon fils);
        wait(&status);
        printf("  status = %d ",status>>8);
    }
  return 0;
}

Affichages :

1
2
3
4
Je suis le fils
Je suis le pere 
  j ’attends la fin de mon fils 
  status = 3

On ne peut pas prédire l'ordre des 3 premiers printf.
Par contre on sait forcément que l'affichage du status se fera en dernier !

  • Lorsqu’un processus se termine (exit), le système détruit son contexte, sauf son entrée de la table des processus
  • Le procesus est alors dit dans un état ZOMBI (momentané si bien codé)
  • Le processus père récupère la mort de son fils (wait), et détruit son entrée de la table des processus.
  • Le fils disparaît complètement du système (n’est plus zombi).

La communication entre le fils zombi et le père s ’effectue par le biais d ’un signal transmis du fils vers le père (signal SIGCHLD : la mort du fils).

Un processus fils défunt reste zombie jusqu’à ce que son père ait pris connaissance de sa mort (wait).

Danger

Une mauvaise synchronisation = saturation table des processus = blocage total du système !


Adoption⚓︎

adopt

Si le père décède avant le fils alors le fils deviendra orphelin et sera adopté par le processus de PID 1 (init).


Exemple de Zombi⚓︎

Warning

Ceci est un code faux ... à des fins pédagogiques !

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
/*Programme pgmzombi.c */
int main(void)
{
    int pid, status;
    pid = fork();
    if (pid == 0) {
        printf(" je suis le FILS pid = %d\n ",getpid());
        sleep(10);
        printf(" je suis le FILS, à dieu\n");
    } else {
        printf("je suis le PERE pid = %d\n",getpid());
        printf("je suis le PERE je boucle à l’infini ");
        for ( ; ; );
    }
  return 0;
}

On suppose que le pid du père est 1234 et celui du fils est 2345.

Résultat de l’exécution en arrière-plan:

> pgmzombi &
    je suis le pere pid =1234
    je suis le pere je boucle à l’infini

    je suis le fils pid =2345
    je suis le fils, à dieu
Avant la mort du fils : Après la mort du fils :
# ps
    1234 tty3 0:04 pgmzombi
    2345 tty3 0:03 pgmzombi
# ps
    1234 tty3 0:04 pgmzombi
    2345 tty3 0:03 [defunct]

Exercice - Zombi War⚓︎

Copiez/Collez ce programme Zombi. Observez vous même le Zombi.
Enfin, corrigez le code afin de le rendre propre !