BCI Informatique - Concurrence

Langage C et sémaphores

Bertrand Dupouy


SOMMAIRE

  1. Présentation du modèle lecteurs/écrivains
    1.1 Rappel du modèle
    1.2 Sémaphores Unix
  2. Synchronisation des seuls lecteurs
    2.1 Exercice
  3. Synchronistion des lecteurs et des écrivains
    3.1 Exercice
  4. Eviter la famine pour les écrivains
    4.1 Exercice
  5. Gestion d'une barrièrre
    5.1 Exercice


1. Présentation du modèle lecteurs/écrivains

Nous allons ici utliser des sémaphores pour synchroniser des processus en suivant la sémantique du modèle lecteurs/écrivains. Pour plus de détails, on trouvera ici le support de cours sur les processus(cf. pages 125 à 129).

1.1 Rappel du modèle

Le fonctionnement du modèle lecteurs/écrivains est le suivant :

1.2 Sémaphores Unix

Les opérations P, V et Init sur les séamaphores sont ainsi implantées sous Unix :
Opération API POSIX C
Init(sem, compteur)
sem = sem_open(Nom, O_CREAT, 0644, compteur)
Signification des paramètres:
  • Nom : Nom du sémaphore, ce nom doit commencer par \
  • O_CREAT : création d un nouveau sémaphore
  • 0644 : droits d'accès (lecture et écriture)
P(sem)
sem_wait(sem);
V(sem)
sem_post(sem);

2. Synchronisation des seuls lecteurs

On utilisera le programme se trouvant ici dans lequel aucune synchronisation n'est faite.

Remarques :

2.1 Exercice

  1. Compiler et exécuter le programme pour vérifier que la synchronisation n'est pas assurée, par exemple :
    ./ecrlec-v0 0 2
    ./ecrlec-v0 2 1

  2. Compléter la partie lecteur seule de ce programme et vérifier son bon fonctionnement. Pour ce faire, si l'exécutable s'appelle ecrlec, on doit obtenir ce type d'affichage :

$ ./ecrlec 0 0
main : ./ecrlec : fin 

$ ./ecrlec 4 0
========================= Lecteur 0 est le premier ->  sem_wait 
========================= Lecteur 0 dans SC --Date :  46:27 
========================= Lecteur 2 dans SC --Date :  46:27 
========================= Lecteur 3 dans SC --Date :  46:27 
========================= Lecteur 1 dans SC --Date :  46:27 
========================= Lecteur 0 va sortir de   SC --Date :  46:37 
main : fin de fils 0000 (hexa)
========================= Lecteur 1 va sortir de   SC --Date :  46:38 
main : fin de fils 0100 (hexa)
========================= Lecteur 2 va sortir de   SC --Date :  46:39 
main : fin de fils 0200 (hexa)
========================= Lecteur 3 va sortir de   SC --Date :  46:40 
========================= Lecteur 3 est le dernier ->  sem_post 
main : fin de fils 0300 (hexa)
main : ./ecrlec : fin 

3. Synchronistion des lecteurs et des écrivains

3.1 Exercice

Compléter la partie écrivain de ce programme, pour le moment on ne traite pas le problème de la famine pour les écrivains.

Les tests à effectuer :

  1. On vérifie d'abord que l'exclusion mutuelle est assurée pour les écrivains :
    
    $ ./ecrlec 0 2
     ******************** Ecrivain 0 Debut :  04:59
     ******************** Ecrivain 0 entre SC -- Date :  04:59 (iteration : 0)
     ******************** Ecrivain 1 Debut :  04:59
     ******************** Ecrivain 0 va sortir SC  -- Date :  05:02 (iteration : 0)
     ******************** Ecrivain 1 entre SC -- Date :  05:02 (iteration : 0)
     ******************** Ecrivain 1 va sortir SC  -- Date :  05:06 (iteration : 0)
     ******************** Ecrivain 0 entre SC -- Date :  05:06 (iteration : 1)
     ******************** Ecrivain 0 va sortir SC  -- Date :  05:09 (iteration : 1)
     ******************** Ecrivain 1 entre SC -- Date :  05:09 (iteration : 1)
     ******************** Ecrivain 1 va sortir SC  -- Date :  05:13 (iteration : 1)
     ******************** Ecrivain 0 entre SC -- Date :  05:13 (iteration : 2)
     ******************** Ecrivain 0 va sortir SC  -- Date :  05:16 (iteration : 2)
     ******************** Ecrivain 1 entre SC -- Date :  05:16 (iteration : 2)
    Ecrivain 0 : fin 
     ******************** Ecrivain 1 va sortir SC  -- Date :  05:20 (iteration : 2)
    main : fin de fils 0000 (hexa)
    Ecrivain 1 : fin 
    main : fin de fils 0100 (hexa)
    main : ./ecrlec : fin 
    -sh-4.2$ 
    
  2. On vérifie ensuite le bon fonctionnement global du modèle, par exemple :
    
    $ ./ecrlec 6 2
     ******************** Ecrivain 0 Debut :  15:48
     ******************** Ecrivain 0 entre SC -- Date :  15:48 (iteration : 0)
     ******************** Ecrivain 1 Debut :  15:48
    ========================= Lecteur 0 est le premier ->  sem_wait 
     ******************** Ecrivain 0 va sortir SC  -- Date :  15:51 (iteration : 0)
     ******************** Ecrivain 1 entre SC -- Date :  15:51 (iteration : 0)
     ******************** Ecrivain 1 va sortir SC  -- Date :  15:55 (iteration : 0)
    ========================= Lecteur 0 dans SC --Date :  15:55 
    ========================= Lecteur 2 dans SC --Date :  15:55 
    ========================= Lecteur 3 dans SC --Date :  15:55 
    ========================= Lecteur 4 dans SC --Date :  15:55 
    ========================= Lecteur 5 dans SC --Date :  15:55 
    ========================= Lecteur 1 dans SC --Date :  15:55 
    ========================= Lecteur 0 va sortir de   SC --Date :  16:05 
    main : fin de fils 0000 (hexa)
    ========================= Lecteur 4 va sortir de   SC --Date :  16:05 
    main : fin de fils 0400 (hexa)
    ========================= Lecteur 5 va sortir de   SC --Date :  16:06 
    ========================= Lecteur 1 va sortir de   SC --Date :  16:06 
    main : fin de fils 0100 (hexa)
    main : fin de fils 0500 (hexa)
    ========================= Lecteur 2 va sortir de   SC --Date :  16:07 
    main : fin de fils 0200 (hexa)
    ========================= Lecteur 3 va sortir de   SC --Date :  16:08 
    ========================= Lecteur 3 est le dernier ->  sem_post 
     ******************** Ecrivain 0 entre SC -- Date :  16:08 (iteration : 1)
    main : fin de fils 0300 (hexa)
     ******************** Ecrivain 0 va sortir SC  -- Date :  16:11 (iteration : 1)
     ******************** Ecrivain 1 entre SC -- Date :  16:11 (iteration : 1)
     ******************** Ecrivain 1 va sortir SC  -- Date :  16:15 (iteration : 1)
     ******************** Ecrivain 0 entre SC -- Date :  16:15 (iteration : 2)
     ******************** Ecrivain 0 va sortir SC  -- Date :  16:18 (iteration : 2)
     ******************** Ecrivain 1 entre SC -- Date :  16:18 (iteration : 2)
    Ecrivain 0 : fin 
     ******************** Ecrivain 1 va sortir SC  -- Date :  16:22 (iteration : 2)
    main : fin de fils 0000 (hexa)
    Ecrivain 1 : fin 
    main : fin de fils 0100 (hexa)
    main : ./ecrlec : fin 
    

4. Eviter la famine pour les écrivains

4.1 Exercice

Pour éviter la famine pour les écrivains on va ajouter un sémaphore et vérifier le fonctionnement du programme.

Exemples de tests :

5. Gestion d'une barrièrre

On veut réaliser une barrièreĀ : tant que N participants ne sont pas arrivés devant la barrière, il faut que chacun d'eux attende qu'elle se lève.
Lorsque le participant numéro N arrive, il lève la barrière et débloque ainsi tous ceux qui attendaient.
Variables partagées : Chaque processus participant va exécuter un programme dont le canevas est le suivantĀ :
   P(S1); /* S1 gere l exclusion mutuelle sur nb */
   nb = nb+1;
   if (nb == N){ /* le dernier est arrive : il leve la barriere */
	nb = nb-1;
	while(nb > 0){
           V(S2);
           nb = nb-1;
	}
	V(S1);
   }
   else {
	V(S1);
	/*  attendre que la barriere se leve */
	P(S2);
   } 

5.1 Exercice