Vous êtes sur la page 1sur 6

Chapitre 3: Communication entre processus

Introduction
L’échange d'information entre processus est appelé communication. Cala est possible via le partage
d'une variable (zone mémoire commune) accessible par les processus désirant communiquer. Deux
schémas de communication seront présentés dans ce cours: le modèle Producteur/Consommateur et
le modèle Lecteur/Rédacteur.

3.1 Modèle Producteur/Consommateur


le problème producteur-consommateur (également connu sous le nom de problème de tampon
borné) est un exemple classique de communication inter processus. Deux processus cycliques, un
producteur et un consommateur, qui partagent un tampon commun de taille fixe. Le producteur
génère successivement des données et les écrit dans le tampon. Le consommateur lit les données du
tampon, les supprime au cours de la lecture et utilise ces données. Le solution du problème doit
respecter la condition qu'aucune donnée ne soit perdue ou dupliquée, les données soient lues par le
consommateur dans l'ordre dans lequel il est écrit par le producteur.

3.1.1 Exemples
• Spool d’impression : des processus utilisateurs préparent des fichiers et déposent des
requêtes au service d'impression. Ces requêtes sont satisfaites par l'un des processus du
service d'impression appelé spool d'impression .
• Un organe d'accès direct à la mémoire (DMA), reçoit des données externes, caractère par
caractère, et les stockent à la vitesse des organes périphériques dans une zone de mémoire
tampon. Un processus spécialisé est alerté pour qu'il puisse les exploiter.
• Une Application peut-être conçue sous forme de cascade de relations de coopération entre
processus. Par exemple un protocole de communication est structuré sous forme de
processus communicant via des tampons partagés. Chaque couche sera représenté par un ou
plusieurs processus. Lorsque un processus d'une couche reçoit un message, il appel les
fonctions adéquates, puis transmit le résultat vers le processus de la couche supérieure.

3.1.2 Réalisation du problème Producteur/consommateur par Sémaphores


Nous supposons que la vitesses relatives des processus est quelconques (débit irrégulier), le tampon
est de taille fixe: N cases (une case = un message) et tampon vide initialement, tout message déposé
est lu une fois et une seule fois. Le producteur ne peut déposer un message dans le tampon s'il n'y a
plus de place libre. Le consommateur ne peut retirer un message depuis le tampon s'il n'y en a pas.
Le consommateur ne doit pas retirer un message que le producteur est en train de déposer. Le
tampon est géré comme une file circulaire ayant deux indexes: l'indexe ip pour la production et
l'indexe ic pour la consommation.
Producteur : Consommateur : 
{  { 
ip=0 ic =0; 
while(true) { while(true){ 
1. produire un message m; 1. si pas de message dans le tampon,
2. s'il n'y a pas de case vide  attendre();
attendre(); 2. retirer le message m de T[ic];
3. déposer  m dans la case T[ip]; 3. ic=(ic+1)%N;
4. ip=(ip+1)%N; 4. si le consommateur est en attente
5. si le consommateur est en attente le le reveillé.
reveillé. 5. Consommer le message m;
   }         }
} } 

1
La solution du problème au moyen des sémaphores nécessite deux sémaphores, un sémaphore
Nvide, initialisé à N (nombre de cases vides, initialement =N), et un sémaphore Nplein initialisé à 0
(nombre de cases pleines, initialement = 0). Le schéma présente une symétrie. Le producteur génère
des cases pleines pour le consommateur. Le consommateur génère des cases vides pour le
producteur. Le tampon est accessible en concurrence par un producteur et un consommateur
simultanés. Nous utilisons deux index ip et ic,initialisées à 0. ip est géré entièrement et seulement
par le producteur, l'autre est géré entièrement et seulement par le consommateur.
Tampon T

0 1 2 3 4 5 6 7

ic ip

ip ic
ic ip
ip

ic

b)
a) c)
a) tampon vide : occupe =0, libre = N (N=8) b)tampon ni plein ni vide : occupe =4, libre = 4 ; c): tampon plein : occupe =N, libre =0

Semaphore Nplein = 0 // le nombre des cases pleines
Semaphore Nvide =N: Semaphore init N // le nombre des cases vides
Message T[N];  //un tampon de taille N
Producteur() Consommateur()
{ {
Message x ; Message x ;
int ip= 0; int ic= 0;
while(true) { while(true) {
    Produire(x);     P(Nplein);
    P(Nvide);     x=T(ip);
    T(ip) = x;     ip=(ip+1)%N;
    ip=(ip+1)%N;     V(Nvide);
    V(Nplein);     Consommer(x);
      }       }
} }

La fonction Produire(x) est une fonction de création de messages, elle peut être une lecture de
données d'une base de donnée ou bien une fonction de lecture de valeurs physiques d'un capteur et
de les transformer en une donnée numérique par exemple ou bien tout autre fonction de création de
messages. La fonction Consommer(x) d'impression par exemple, de transfert, de sauvegarde ….

2
3.1.3 Solution du problème Producteur/Consommateur par Moniteurs

monitor Tampon{
message T[N]; /*tableau de messages*/
int NbMsg =0; /* compteur de messages dans le tampon*/
int ip =0,ic=0; /*indexes des producteurs et des consommateurs*/
condition Nplein, Nvide;
void deposer(message m)
{
    if(NbMsg == N){wait(Nplein);}
    T[ip]= m;
    ip = (ip + 1)%N ;
    NbMsg++;
    signal(Nvide) ;
}

message retirer()
{
    if(NbMsg == 0){wait(Nvide);}
    m= T[ic];
    ic = (ic + 1)%N ;
    NbMsg­­;
    signal(Nplein);
    return m;
}
Tampon(){// initialisation du moniteur
    NbMsg=0;
    ip=0;
    ic=0;
 }
}

3.1.4 Solution du problème Producteur/Consomateur par Région critiques

Toutes les variables sont groupés dans une structure de donnée «shared» appelée Tampon.

Shared Struct  Tampon
{
message T[N]; /*tableau de messages*/
int NbMsg =0; /* compteur de messages dans le tampon*/
int ip =0,ic=0; /*indexes des producteurs et des consommateurs*/
}

3
Producteur() Consommateur()
{ {
Message x ; Message x ;
while(true) { while(true) {
  Produire(x);   region Tampon when (NbMsg>0)do
  region Tampon when (NbMsg<N)do   {
  {     x=T(ip);
    T(ip) = x;     ip=(ip+1)%N;
    ip=(ip+1)%N;     NbMsg­­;    
    NbMsg++;    }
   }   Consommer(x);
  }  }
} }

3.2. Modèle Lecteur/Rédacteur

Considérons une situation où nous avons un fichier (une base de données par exemple) partagé
entre plusieurs processus. Si un processus essaie de modifier la base, aucune autre ne doit lire ou
écrire en même temps, sinon les modifications ne lui seront pas visibles. Cependant, si un processus
lit la base, d'autres peuvent le lire en même temps. C'est précisément dans un SE que nous appelons
cette situation le problème des lecteurs-redacteurs.
Paramètres du problème:
• Un ensemble de données (fichier, base de donnée …) est partagé entre plusieurs processus.
• Une fois qu'un rédacteur est prêt, il exécute son écriture. Un seul rédacteur peut écrire à la
fois.
• Si un processus est en cours d'écriture, aucun autre processus ne peut le lire.
• Si au moins un lecteur lit, aucun autre processus ne peut écrire.
• Plusieurs processus peuvent lire ensembles.

3.2.1 Lecteurs/rédacteurs par semphores

Les vitesses relatives des processus sont quelconques, les priorités ou les droits des processus sont
quelconques, tout processus termine son écriture et/ou sa lecture au bout d'un temps fini
la solution doit permettre les lectures en parallèle et interdire la lecture et l’écriture en parallèle et
l’écritures en parallèle.
Nous utilisons :
• Une variable entière NL qui est un compteur représentant le nombre de lecteurs en cours.
• Un sémaphore d'exclusion mutuelle Mutex utilisé entre les accès de tout rédacteur et d'un
groupe de lecteur.
• Un sémaphore d'exclusion mutuelle MutexL utilisée entre les lecteurs
Un rédacteur bloqué est réveillé par un autre rédacteur qui sort de section critique ou par le dernier
lecteur qui finit de lire dans un groupe de lecteurs.
Si un lecteur est réveillé par un rédacteur, il réveil tout les autre lecteurs en attente.
Remarque : La solution n'est pas équitable. S'il n'y a jamais de dernier lecteur dans un groupe (il
suffit pour cela que les entrées dans le groupe soient toujours supérieures aux sorties du groupe), les
lecteurs se coalisent et c'est la famine pour les rédacteurs.

4
Semaphore  Mutex=1, MutexL=1 ;
int NL = 0;
Lecteur() Redacteur()
{ {
    P(MutexL);
    NL++;   P(Mutex);
    if (NL == 1) P(Mutex);   /*Ecritures*/
    V(MutexL);   V(Mutex);
   /*Lectures*/ }
    P(MutexL);
    NL­­;
    if (NL==0)V(Mutex);
    V(MutexL);
}

3.2.2 Lecteurs/rédacteurs par Moniteurs

Monitor lec_red {

boolean ecr;/*true s'il y a lecture en cours, faux sinon*/
int nl; /*compteur de lecteurs present*/
condition c_ecr, c_lect;

void debut_lire()
{
    nl++;
    if (ecr) wait(c_lect) ;
    signal(c_lect);
}

void fin_lire();
{
    nl­­;
    if(nl==0)signal(c_ecr);
}

void debut_ecrire();
{
    if (ecr || nl>0) wait(c_ecr) ;
    ecr = true ;
}

void fin_ecrire()
{
    ecr = false ;
    if (nl > 0) signal(c_lect);
    else signal(c_ecr) ;
}

5
lec_red(){   /*constructeur du moniteur*/
    ecr = false ;
    nl = 0 ;
    }
}/*fin du moniteur*/

3.2.3 Lecteurs Rédacteurs par régions critiques 

Shared Struct LecRed{
int NL=0;
Boolean ecr = false ;
}

Lecteur()
{
    region LecRed when (!ecr) do NL++;
    <Lectures>;
    region LecRed do NL­­;
}

Redacteur()
{
    region LecRed when (!ecr && NL<=0)do
        {
        ecr=true
        }    
    <Ecriture>;    
    region LecRed do ecr=false;
}

Vous aimerez peut-être aussi