Correction du partiel de Systèmes -- Master 1-II -- Nov. 2007

Exercice « méfions-nous des fork() »

  1. Lorsqu'on exécute a, 7 processus sont ensuite créés (on ne compte pas ici le processus de départ lui-même, sinon la réponse est 8).
  2. Rappelons qu'un appel à exec() ne créé pas de nouveau processus mais recouvre le code du processus courant par le code contenu dans le fichier donné en argument; ensuite l'exécution est transférée à la fonction main() de ce nouveau programme.
    Donc, le programme passe son temps à créer un processus fils puis à se recouvrir ensuite par lui-même (et donc à refaire la même chose indéfiniment). Le nombre de processus créé est potentiellement infini (pour vous fâcher avec votre administrateur système vous pouvez essayer, exercice: demandez-vous comment arrêter ce monstre...).
  3. Il n'y aurait alors aucune création de processus après le lancement du programme car celui se recouvrirait par lui-même indéfiniment.

Exercice « on ne peut pas compter sur la simple lecture des programmes »

La condition du while est fausse lorsque le retour de l'appel à fork() s'effectue dans le père, ou qu'il s'effectue dans le fils et que la variable i (avant son incrémentation) est égale ou plus grande que N. En sortie du while on affiche la valeur de la variable i.
Donc, le premier processus créé affiche 0, son fils 1, son petit fils 2, ainsi de suite jusqu'à la génération N+1. Les nombres de 0 à N+1 sont affichés dans le désordre car nous ne pouvons faire aucune hypothèse sur l'ordonnancement des processus qui sont ici en concurrence. Il est toutefois assez probable que l'ordre effectif soit proche de l'ordre naturel défini sur les entiers.

Le point délicat est de bien voir que le plus grand entier généré est bien N+1. En effet, supposons que i, soit égale à N-1, le fork() s'exécute, le fils réalise que lacondition est vraie et incrémente la variable qui vaut alors N, un nouveau fork() s'exécute et le fils réalise que la condition est désormais fausse, mais son effet de bord est d'incrémenter la variable qui vaut alors N+1. Cette subtilité n'est pas importante, le point crucial est d'affirmer que l'ordre n'est pas garanti.

Exercice « wait() ou pas wait() ? Telle est la question »

  1. void fils(int n,void (*g)()) {
      int i;
      for (i=0; i<n; i++)
        if (fork()==0) {
          g();
          exit(0);
        }
    }
    

    On peut se poser la questiondes zombies (c'est vrai que ça fait peur)... Auquel cas le père pourrait s'écrire:

    void fils(int n,void (*g)()) {
      int i;
      for (i=0; i<n; i++)
        if (fork()==0) {
          g();
          exit(0);
        }
      for (i=0; i<n i++) wait(NULL);
    }
    
  2. Pour cette question il suffit (par exemple) que le père attende la terminaison du fils:
    void fils(int n,void (*g)()) {
      int i;
      for (i=0; i<n; i++)
        if (fork()==0) {
          g();
          exit(0);
        } else {
          wait(NULL);
        }
    }