Tux

Unix : Programmation Système

TD 7 - Les Semaphores

C. Drocourt
I.U.T. Amiens
drocourt@iut-amiens.fr

Exercice  :

Le but du TD
Implanter le graphe de précédence ci-contre avec deux sémaphores et cinq processus s’exécutant en parallèle ; un processus (le père) est chargé de les lancer (grâce à fork) après avoir créé et initialisé l’ensemble de sémaphores.

Ce graphe veut dire :
– T2, T3 et T4 ne s'exécuteront que lorsque T1 sera terminée.
– T5 ne s'exécutera que lorsque T2, T3 et T4 seront terminées.

Les actions que doivent réaliser les processus sont :
– T1 : dormir 3 secondes
– T2 : dormir 20 secondes
– T3 : dormir 1 seconde
– T4 : dormir 4 secondes
– T5 : dormir 2 secondes

Les synchronisations sont assurées par les sémaphores S et U selon l’algorithme suivant :

créer et initialiser le sémaphore S à 0.
créer et initialiser le sémaphore U à 0.
Lancer simultanément T1 jusque T5 avec :
    T1 : sleep(3); V(S); V(S); V(S);
    T2 : P(S); sleep(20); V(U);
    T3 : P(S); sleep(1) ; V(U);
    T4 : P(S); sleep(4) ; V(U);
    T5 : P(U); P(U); P(U); sleep(2);

On précise, par exemple, que V(S) veut dire exécuter l'opération V1 sur le sémaphore S (incrémenter de 1 le sémaphore S) et que P(U) signifie exécuter l'opération P1 sur le sémaphore U (décrémenter de 1 le sémaphore U).

On rappelle en outre que l'on considère les opérations P et U au sens Unix :
- Opération Pn(S)
     Si S>=n, S=S-n
     Si S<n, mise en attente du processus
- Opération Vm(S)
     S=S+m et réveil des processus en attente de l’augmentation de la valeur de ce sémaphore

On décide d'implémenter ceci sous C et on rédige le programme C ci-dessous.

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


main(void) {

    int semid,i;
   
/* création d'un ensemble de DEUX sémaphores: sémaphore S premier sémaphore, sémaphore U deuxième sémaphore */

    semid=semget(IPC_PRIVATE,2,IPC_CREAT|IPC_EXCL|0600);
1

2
    for(i=0;i<5;i++)
      if(fork() == 0)
        switch(i)
        {
          case 0:     sleep(3);
                      V(semid,0);
                      V(semid,0);
                      V(semid,0);
                      exit(0);     3

          case …

                                    Ì
       } /* switch */
4

5

6
    exit(0);
}



On donne le prototype et le rôle des fonctions P et V.

int P(int semid, int NS);
Cette fonction décrémente de un le sémaphore numéro NS de l'ensemble de sémaphore semid.

int V(int semid, int NS);
Cette fonction incrémente de un le sémaphore numéro NS de l'ensemble de sémaphore semid.

Questions :

1 – Compléter la partie 1 pour tester la réussite de la création de l’ensemble de sémaphore,
2 – Rédiger la partie 2 correspondant à l'initialisation des deux sémaphores à zéro,
3 – Compléter la partie 4 correspondant à la création des différents processus T2 jusque T5,
4 – Rédiger la partie 5 correspondant à l'attente du père de ses cinq fils,
5 – Rédiger la partie 6 correspondant à la destruction par le père de l'ensemble de sémaphore,
6 – Pourquoi est-il nécessaire de placer une instruction exit à la ligne 3 du programme ?
7 – Ecrire les fonctions P et V. On prendra soin de renvoyer un code de retour conforme à « l’esprit Unix ».