Académique Documents
Professionnel Documents
Culture Documents
Les Processus :
La Synchronisation avec
les sémaphores
-2-
Synchronisation des processus avec sémaphores
1. Introduction
2. Défintion
3. Comment exprimer les contraintes de synchronisation ?
4. Spécification de la synchronisation
5. Les problèmes types
6. Exemples
6.1 Allocation d’une imprimante
6.2 Rendez-vous
6.2.1 Rendez-vous de deux processus
6.2.2 Rendez-vous de trois processus
6.2.3 Rendez-vous de n processus
6.3 Le modèle des lecteurs/rédacteurs
6.3.1 Ordre d’accès au fichier est quelconque
6.3.2 Ordre d’accès au fichier est FIFO
-3-
6.4 Communication par variables communes
6.4.1 Définitions
6.4.2 Propriétés de la communication
6.4.3 Schéma général du producteur-consommateur
6.4.4 Producteur-consommateur avec un tampon à un seul élément
6.4.5 Producteur-consommateur avec un tampon à n éléments
6.4.6 Plusieurs producteurs et plusieurs consommateurs
6.4.7 Producteur-consommateur avec un tampon à éléments alloués
dynamiquement
7. La communication interprocessus : IPC Unix System V
7.1 Introduction
7.2 Identification d’une IPC
7.3 Les segments de mémoire partagée
7.3.1 Utilisation d’un segment de mémoire partagée
7.3.2 Fonctions de manipulation des segments de mémoire partagée
7.3.3 Exemple : Création et d’utilisation d’un segment de mémoire
partagée -4-
7.4 Les Sémaphores Unix System V
7.4.1 Utilisation des sémaphores Unix system V
7.4.2 Création d’un ensemble de sémaphores
7.4.3 Initialisation d’un ensemble de sémaphores
7.4.4 Opérations sur un ensemble de sémaphores
7.4.5 Destruction d’un sémaphore
7.4.6 Exemple
7.5 Gestion des IPC avec des commandes shell
-5-
La Synchronisation des processus
1. Introduction
Exemple :
➢ Soient deux Processus concurrents P1 et P2 qui coopèrent pour lire et
imprimer le contenu d’un fichier f.
➢ Le fichier f est composé d’un ensemble d’articles.
➢ On dispose de deux procédures :
• Lire(f, article): permet de lire un article du fichier f et le ranger
dans la zone utilisateur d’adresse « article ».
• Ecrire(article) : permet d’afficher/imprimer le contenu de la zone
utilisateur « article » sur l’écran/l’imprimante.
➢ On dispose en mémoire centrale d’un seul tampon qui est partagé par
les deux processus.
-6-
-7-
tampon T init(‘’’’); /* T: initialiser à vide */
Processus P1 Processus P2
Structure … artcle1; Structure … artcle2;
Début Début
Lire(article1,f);
Tantque (non(fin(f)) faire Tantque (T # ‘’fin’’) faire
Déposer (article1,T); Retirer(article2,T);
Signaler(dépôt); Signaler(retrait);
Lire(article1,f); Ecrire(article2);
Finfaire; Finfaire;
T=‘’fin’’; Fin;
Fin;
-8-
Déposer(article,T) Retirer(article,T)
Début Début
Si tampon T est plein alors Si T est vide alors
Attendre; Attendre;
T = article; Article = T;
Fin; Fin;
- 11 -
3. Comment exprimer les contraintes de
synchronisation ?
1. Imposer un ordre de précédence dans le temps logique, pour l’exécution
des actions des processus .
Exemples:
a) La précédence
Exécuter l’action i du processus P1 avant l’action j du processus P2.
b) Le rendez-vous
Deux étudiants de fixent un rendez-vous pour travailler ensemble.
Etudiant 1 Etudiant 2
Début Début
. . . . . .
Attendre étudiant 2; Attendre étudiant1;
Travailler ensemble; Travailler ensemble;
Fin; Fin;
- 12 -
La forme d’un programme de rendez-vous
Debut i
. . .
Rendez-vous i; *
* Suite i;
Fin i
* i, j : fin(rendez-vous i) avant début(suite j)
Aucun processus i ne peut exécuter la séquence suite i que si tous
les autres processus sont arrivés à leur point de rendez-vous.
Processus P1 Processus P2
Lire(article1,f);
tantque(non(fin(f))faire Tantque T ‘’fin’’ faire
Déposer (article1,T); Retirer(article2,T);
Signaler(dépôt); Signaler(retrait);
Lire(article1,f); Ecrire(article2);
Finfaire; Finfaire;
T=‘’fin’’;
•- 15 -
● Points de synchronisation :
Déposer (article1,T), Retirer(article2,T), Signaler(dépôt) et
Signaler(retrait).
• Variable d’état:
Etat du tampon (vide ou plein).
- 16 -
5. Les problèmes types
● Les problèmes de synchronisation rencontrés dans la pratique
peuvent, dans leur grande majorité, se ramener à des combinaisons
d’un petit nombre de situations élémentaires pour lesquelles des
schémas de solutions sont connus.
● Les problèmes types peuvent être regroupés en trois classes:
1) Exclusion Mutuelle(première partie de ce chapitre)
Processus i
Début
Demander(imprimante); Demande d’entrée en section critique
<Utiliser l'imprimante > < section critique >
Restituer(imprimante); Sortie de la section critique;
Fin;
• L’imprimante a deux états libre ou occupé. - 18 -
● Solution avec les sémaphores
Soit slibre le sémaphore d’exclusion mutuelle protégeant cette
imprimante :
Sémaphore slibre init 1;
Processus i
Début
P(slibre);
<Utiliser l'imprimante ; >
V(slibre);
Fin;
- 19 -
b) m processus se partagent n imprimantes
Schéma général d’un processus i :
Processus i
Début
Demander(imprimante);
<Utiliser l'imprimante ; >
Restituer(imprimante);
Fin;
Il y a n imprimantes n processus sur m peuvent travailler
(imprimer) simultanément : C’est une ressource critique à n points
d’entrée.
Demander(imprimante) Restituer(imprimante)
Début Début
P(slibre); V(slibre);
Fin Fin
- 22 -
4) Deux Variables d’état
Les variables d’état représentent :
• Le nombre de ressources(imprimantes) demandées : nbd,
• Le nombre de ressources(imprimantes) occupées : nbo.
• Soit nbimp une variable ou constante système contenant le nombre
d’imprimantes.
Entier nbimp init n;
Entier nbo init 0 ; Entier nbd init 0 ;
Demander(imprimante) Restituer(imprimante)
Début Début
nbd = nbd + 1; nbo = nbo - 1;
si nbo = nbimp alors attendre; Si nbd > 0 alors
Sinon nbd = nbd - 1;
nbd = nbd - 1; nbo = nbo + 1;
nbo = nbo + 1; Réveiller un processus;
finsi finsi;
Fin Fin
- 23 -
Solution à l’aide des sémaphores :
- 24 -
Entier nbimp init n; /* variable ou constante */
Entier nbo init 0; Entier nbd init 0;
Sémaphore s init 0;
Demander(imprimante) Restituer(imprimante)
Début Début
nbd = nbd + 1; nbo = nbo - 1;
Si nbo == nbimp alors Si nbd > 0 alors
nbd = nbd – 1;
nbo = nbo + 1;
/*Attendre */ /* Réveiller un processus */
P(s); V(s);
Sinon Finsi
nbd = nbd - 1;
nbo = nbo + 1;
Finsi
Fin Fin
P1 P2 P3
Début Début Début
… … …
Signaler son arrivée Signaler son arrivée Signaler son arrivée
à P2 et P3; à P1 et P3; à P1 et P2;
Attendre P2 et P3; Attendre P1 et P3; Attendre P1 et P2;
… … …
Fin Fin Fin
On utilise deux sémaphores de synchronisation initialisés à 0.
Sémaphore s1, s2, s3 init 0;
P1 P2 P3
Début Début Début
… … …
V(s2); V(s3); V(s1); V(s3); V(s1); V(s2);
P(s1); P(s1); P(s2); P(s2); P(s3); P(s3);
… … …
Fin; Fin; Fin; - 28 -
6.2.3 Rendez-vous de n processus : P0 à Pn-1
a) Solution avec une variable partagée(par les n processus) et deux
sémaphores :
● La variable c’est un compteur qui permet de compter les
arrivées des processus(nombre de processus arrivés).
● Deux sémaphores:
✓ Cette variable est partagée donc elle doit être protégée par
un sémaphore d’exclusion mutuelle initialisé à un.
✓ Un sémaphore de synchronisation permettant de mettre en
attente les processus; ce sémaphore est initialisé à zéro.
- 29 -
1) Le dernier processus réveil les (n-1) processus précédents
Processus i (i=0 à n-1)
Début
P(mutex);
cpt=cpt +1;
Si cpt < n alors /* processus 0 à n-2 */
V(mutex); /* Sortir de la SC avant de se mettre en attente */
p(s); /* se mettre en attente */
Sinon /* dernier processus*/
cpt=0;
v(mutex); /* Sortir de la SC */
/* réveiller le (n-1) processus */
Pour j=1 à n-1 faire
v(s);
finpour
Finsi;
Fin
- 30 -
2) Réveil en ‘‘cascade ’’
Processus i (i=0 à n-1)
Début
P(mutex);
cpt=cpt +1;
Si cpt < n alors /* processus 0 à n-2 */
V(mutex); /* Sortir de la SC avant de se mettre en attente */
P(s); /* se mettre en attente */
V(s); /* Réveiller le processus suivant */
Sinon /* dernier processus*/
cpt=0;
V(mutex); /* Sortir de la SC */
V(s); /* réveiller le premier processus */
P(s); /* se mettre en attente */
/* le dernier processus est réveillé par l’avant dernier */
Finsi
Fin
- 31 -
6.3 Le modèle des lecteurs/rédacteurs
➢ Considérons deux classes de processus appelés : Lecteurs et
Rédacteurs.
➢ Ces processus se partagent un fichier f.
- 34 -
Sémaphore sf init 1;
Entier nl init 0;
Sémaphore mutex init 1;
Lecteurs Rédacteurs
Début Début
/* demande de lecture */ /* demande d'écriture */
p(mutex); p(sf);
nl=nl+1;
si nl=1 alors p(sf); < écrire >
v(mutex);
< lire > /* fin d'écriture */
/* fin de lecture */ v(sf);
p(mutex); Fin;
nl=nl-1;
si nl=0 alors v(sf);
Remarque : Risque de
v(mutex);
privation pour les rédacteurs.
Fin; - 35 -
6.2.2 Ordre d’accès au fichier f selon FIFO
Sémaphore sf init 1;
Sémaphore sfifo init 1; /*sémaphore imposant l’ordre d’accès FIFO */
Entier nl init(0);
Sémaphore mutex init 1;
Lecteurs Rédacteurs
Début Début
/* demande de lecture */ /* demande d'écriture */
P(sfifo); P(sfifo);
p(mutex); p(sf);
nl=nl+1; V(sfifo);
si nl=1 alors p(sf);
v(mutex); < écrire >
V(sfifo);
< lire > /* fin d'écriture */
/* fin de lecture */ v(sf);
p(mutex); Fin;
nl=nl-1;
si nl=0 alors v(sf);
v(mutex);
Fin; - 36 -
6.4 Communication par variables communes
6.4.1 Définitions
• Soit T un tampon(buffer) accessible à l’ensemble des processus
voulant communiquer.
• On distingue deux classes de processus :
1. Producteur : processus désirant déposer de l’information dans
un tampon T
2. Consommateur : un processus désirant retirer de l’information
d’un tampon T.
- 37 -
6.4.2 Propriétés de la communication
La communication par variable(s) commune(s) est :
✓ Indirecte : le producteur et le consommateur ne s’adressent pas
l’un à l’autre.
- 38 -
➢ Deux types de problèmes à traiter dans la communication par
variables communes :
1. La synchronisation des processus
• Un producteur ne peut déposer un message que s’il y a de la
place disponible dans le tampon(buffer).
• Un consommateur ne peut retirer un message que s’il y en a de
disponible.
• Les producteurs et les consommateurs ne peuvent accéder
simultanément au tampon que selon certaines règles assurant
l’intégrité de l’information.
2. La transmission
C'est le moyen par lequel l’information est communiquée :
Elle concerne la gestion du tampon T.
- 39 -
6.4.3 Schéma général du producteur-consommateur
• Le système de communication : il est composé
✓ du tampon : T,
✓ du mécanisme de synchronisation : Sémaphores ,
✓ des primitives de communication :
Envoyer(message) et Recevoir(message).
• Soient
✓ Un producteur désirant envoyer un message Mp dans un système
de communication et
✓ Un consommateur désirant retirer un message Mc de ce même
système de communication.
- 40 -
Producteur Consommateur
Répéter Répéter
Produire(Mp); Recevoir(Mc);
Envoyer(Mp); Consommer(Mc);
Jusqu’à faux; Jusqu’à faux;
Fin; Fin;
• Décomposant les procédures Envoyer et Recevoir en séparant le
problème de synchronisation et de celui de la transmission :
Producteur Consommateur
Procédure Envoyer(Mp) Procédure Recevoir(Mc)
Demande de dépôt ; Demande de retrait;
Déposer(Mp); Retirer(Mc);
Signaler dépôt; Signaler retrait;
Fin; Fin;
• Synchronisation : Demande de dépôt, Signaler dépôt,
Demande de retrait, signaler retrait.
- 44 -
6.4.5 Producteur-Consommateur avec un tampon à n éléments
• Nombre fixe d’éléments du tampon égal à n.
• n est connu par le producteur et le consommateur.
• Un producteur ne peut déposer une information dans un élément
du tampon que si le consommateur a retiré la précédente.
• Les éléments du tampon sont consommés dans le même ordre que
leur production.
• Chaque élément du tampon à deux états : plein et vide.
• Producteur : Déposer s’il y a un élément vide dans le tampon.
• Consommateur : Retirer s’il y a un élément plein dans le
Tampon.
- 45 -
• Réalisation avec les sémaphores
a) Synchronisation
✓ On associe deux sémaphores splein et svide au tampon T.
✓ splein et svide initialisés respectivement à zéro et n.
✓ Les procédures de synchronisation ne changent pas : elles sont les
mêmes , on ne change que l’initialisation du sémaphore svide.
Sémaphore splein init 0;
Sémaphore svide init n;
Producteur Consommateur
Début Début
Répéter Répéter
Produire(Mp) P(splein);
P(svide); Retirer(Mc)
Déposer(Mp) V(svide);
V(splein); Consommer(Mc);
Jusqu’à faux; Jusqu’à faux;
Fin; Fin;
- 46 -
b) Gestion du tampon à n éléments
● Allocation statique du tampon.
● Le tampon sera géré de manière circulaire: On l'appelle tampon
circulaire ou buffer circulaire.
● Les éléments du tampon sont numérotés de 0 à n-1.
● Dans un tampon circulaire, on considère l'élément 0 comme le
successeur de l'élément n-1.
Déposer(Mp) Retirer(Mc)
T[in]:= Mp; Mc := T[out];
in :=(in +1) modulo n; out:=(out +1) modulo n;
Fin; Fin; - 48 -
T: tableau[0..n-1] de tampon;
Sémaphore splein init 0;
Sémaphore svide init n;
Producteur Consommateur
Entier in init(0); Entier out init(0);
Début Début
Répéter Répéter
Produire(Mp) P(splein);
P(svide); Mc := T[out];
T[in]:= Mp; out:=(out +1) modulo n;
in :=(in +1) modulo n; V(svide);
V(splein); Consommer(Mc);
Jusqu’à faux; Jusqu’à faux;
Fin; Fin;
- 49 -
6.4.6 Plusieurs producteurs(P) et plusieurs consommateurs(C)
Ce cas pose un problème d'exclusion mutuelle au niveau de la gestion
du tampon (ou dans les procédures Déposer et Retirer):
- 50 -
➢ Pour parcourir le tampon, chaque classe de processus (producteurs ou
consommateurs) aura son propre pointeur:
● In : pointeur (ou index) utilisé par les producteurs, c’est une
variable commune aux producteurs : ils doivent l'utiliser en
exclusion mutuelle.
● Out : pointeur (ou index) utilisé par les consommateurs. C’est une
variable commune aux consommateurs : ils doivent l'utiliser en
exclusion mutuelle.
● Les deux variables sont initialisées à 0(zéro).
● Pour protéger les variables communes in et out, on aura besoin de
deux sémaphores d'exclusion mutuelle sin et sout.
● sin et sout sont initialisés à 1.
- 51 -
Sémaphore sin init (1); Sémaphore sout init (1);
Déposer(Mp) Retirer(Mc)
p(sin); p(sout);
T[in]:= Mp; Mc := T[out];
in :=(in +1) modulo n; out:=(out +1) modulo n;
v(sin); v(sout);
Fin; Fin;
- 52 -
T: tableau[0..n-1] de tampon;
Sémaphore splein init 0;
Sémaphore svide init n;
Producteurs Consommateurs
Entier in init 0; Entier out init 0;
Sémaphore sin init 1; Sémaphore sout init 1;
Producteur i Consommateur i
Début Début
Répéter Répéter
Produire(Mp) P(splein);
P(svide); P(sout);
P(sin); Mc := T[out];
T[in]:= Mp; out:=(out +1) modulo n;
in :=(in +1) modulo n; V(sout);
V(sin); V(svide);
V(splein); Consommer(Mc);
Jusqu’à faux; Jusqu’à faux;
Fin; Fin;
- 53 -
6.4.7 Producteur-Consommateur avec tampon à éléments alloués
• Les éléments du tampon sont alloués dynamiquement en faisant appel
à une fonction système(ou à un allocateur de mémoire).
• Le nombre d’éléments du tampon est variable il n’est pas connu à
l’avance.
• Dans ce cas, une partie du problème de synchronisation se trouve
reporter au niveau de "l'allocateur de la mémoire".
• L’allocateur de la mémoire a pour rôle :
✓ d'allouer aux producteurs qui lui demandent un élément de tampon,
✓ de libérer les éléments restitués par les consommateurs.
❖ Allocateur
Procédure allouer( élément);
Procédure restituer(élément);
Fin;
- 54 -
➢ Réalisation des procédures au moyen des sémaphores
● Considérons deux primitives allouer(élément) et
restituer(élément) permettant respectivement l'allocation et la
libération d'un élément du tampon.
● On utilise un seul sémaphore splein initialisé à zéro.
● Ce sémaphore permet d'une part, au producteur de signaler le
dépôt de messages et d'autre part, il permet au consommateur de
vérifier la présence de message dans le tampon.
Tampon *T; /* le tampon est une liste */
splein: sémaphore init 0;
Procédure Demande_de_dépôt Procédure Demande_de_retrait
Allouer(élément); P(splein);
Fin; Fin;
Producteur Consommateur
Début Début
Répéter Répéter
Produire(Mp) P(splein);
Allouer(élément); Retirer(T, Mc, élément);
Déposer(T, élément, MP); Restituer(élément);
V(splein); Consommer(Mc);
Jusqu’à faux; Jusqu’à faux;
Fin; Fin;
- 56 -
❖ Sémaphore binaire
Pb(s) Vb(s)
Début Début
Si s=1 alors Si f(s) est vide alors
s=0; s=1;
Sinon Sinon
Mettre le processus dans la Retirer un processus de la
file f(s); file f(s);
/*bloquer le processus*/ /*réveiller un processus*/
Finsi Finsi
Fin Pb; Fin Vb;
- 57 -
7. La communication interprocessus :
IPC Unix System V
7.1 Introduction
• Les processus concurrents sont créés pour participer à la réalisation
d’une application commune.
• Ces processus se partagent des informations communes qu’ils peuvent
consulter ou modifier au cours de leur exécution.
• Ces processus peuvent être crées dans un même programme(ils ont le
même père) ou créés dans des programmes différents.
• La communication interprocessus(IPC : InterProcess Communication)
permet à un ensemble de processus concurrents , s’exécutant sur une
même machine, de communiquer entre eux en respectant certaines
règles.
- 58 -
Types de communications IPC System V
- 59 -
7.2 Identification d’une IPC
• Une IPC (segment de mémoire ou sémaphore) est identifiée à l’aide
d’une clé unique connue par tous les processus coopérants
utilisant cette ressource partagée.
- 63 -
• Un segment de mémoire partagée doit être créé et détruit
explicitement par un des processus concurrents.
• Remarque : Après la terminaison des tous les processus utilisant un
segment de mémoire partagée, le système ne détruit pas ce segment.
7.3.1 Utilisation d’un segment de mémoire partagée
Un processus désirant utiliser un segment de mémoire partagée doit faire
les actions suivantes :
1) Obtenir une clé(publique ou privée) qui permet d’identifier le
segment,
2) Créer le segment de mémoire partagée,
3) Attacher le segment de mémoire partagée à son espace d’adressage,
4) Utiliser le segment de mémoire partagée,
5) Détacher le segment de mémoire partagée,
6) Détruire le segment(si dernier processus utilisant le segment et si
c’est le processus créateur).
- 64 -
7.3.2 Fonctions de manipulation des segments de mémoire
partagée
- 65 -
1) Création d’un segment de mémoire partagée
int shmget(key_t cle, int taille, int options);
✓ cle : clé obtenue avec ftok() ou IPC_PRIVATE.
✓ taille : indique la taille en octets du segment de mémoire partagée.
Si le segment existe déjà, la taille doit être inférieure ou égale à
la taille effective du segment.
La taille est arrondie au multiple supérieur de la taille des
pages mémoire du système (4Ko sur un processeur Intel).
✓ options : OU (|) binaire entre IPC_CREAT, IPC_EXCL et les 9 bits
d'autorisation.
adr= shmget (cle, 4096, IPC_CREAT | 0666);
0 : pour indiquer que ‘666’ est une valeur octale.
‣ IPC_CREAT : Créer un nouveau segment de mémoire partagée s’il
n’y a pas de segment associé à la clé <cle>.
S’il existe déjà un segment associé à la clé indiquée,
la fonction renvoie l’identificateur de ce segment.
- 66 -
‣ IPC_EXCL : toujours utilisé avec IPC_CREAT, permet de créer
un nouveau segment. S’il existe déjà un segment
associé à la clé indiquée, abandonner la fonction
shmget (erreur : pas de création de segment).
‣ Bits d'autorisation : 9 bits; propriètaire(rw-), membres du
goupe(rw-), autres(rw-).
Remarques :
a) Le bit x(exécution) n’est pas utilisé(-): il n’ y a pas d’exécution
d’un segment de mémoire partagée(données).
b) Ne pas oublier de préciser les autorisations(permissions) d’accès
lors de la création d’un segment de mémoire partagée. Sinon le
segment aura la protection 000 (en octal). Aucun accès.
• La fonction retourne un identificateur du segment de mémoire
partagée.
• Ce segment n’est pas encore utilisable, Le processus doit l’attacher à
son espace d’adressage à l’aide la fonction shmat().
- 67 -
2) Attachement d’un segment de mémoire partagée à l’espace
d’adressage d’un processus
char *shmat(int shmid, char *adr, int options);
✓ shmid : identificateur de segment de mémoire partagée créé avec
shmget.
✓ adr : adresse désirée de l'attachement, elle est rarement utilisée.
On met la valeur NULL ou 0 et c’est le système qui choisit un
emplacement libre(une adresse) dans l’espace d’adressage du
processus. Solution à utiliser dans les TP.
✓ options : SHM_RDONLY : l’attachement est réalisé en lecture seule,
0 : l’attachement est réalisé en lecture et écriture.
• La fonction retourne l’adresse du premier octet du segment ou -1 si
erreur.
return 0;
}
- 71 -
7.4 Les sémaphores Unix system V
• Le partage de segment de mémoire partagée nécessite une
coordination(synchronisation) des actions des processus qui l’utilisent.
• Cette coordination(synchronisation) est assurée au moyen des
sémaphores Unix SystemV.
7.4.1 Utilisation des sémaphores Unix system V
• Obtenir une clé(publique ou privée) qui permet d’identifier un
ensemble de sémaphores(un ou n sémaphores),
key_t ftok (char *chemin d’accès, char projet);
• Créer un ensemble de un ou n sémaphores : semget(),
• Initialiser ce ou ces sémaphores : semctl(),
• Utiliser les sémaphores pour synchroniser les actions des processus
concurrents(opérations P et V ou autre opération) : semop(),
• Détruire le ou les sémaphores(si dernier processus utilisant ce(s)
sémaphore(s) et si c’est le processus créateur) : semctl().
- 72 -
7.4.2 Création d’un ensemble de sémaphores
La création est réalisée à l’aide la fonction semget().
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>
- 74 -
7.4.3 Initialisation d’un ensemble de sémaphores
Il est possible de réaliser certaines opérations de contrôle sur un ensemble
de sémaphores grâce à la primitive semctl() :
int semctl (int idf_sem, int num_sem, int commande, union semun arg);
- 75 -
✓ commande : commande permettant de contrôler l'ensemble de
sémaphores.
‣ SETVAL : affectation d'une valeur précise dans le sémaphore
référencé par num_sem (ou dont le numéro se trouve dans
num_sem)
‣ SETALL : affectation d'une valeur précise dans tous les
sémaphores de l'ensemble.
✓ union semun {
int val;
struct semid_ds *buf; /* voir le man */
unsigned short *array;
} arg;
‣ arg.val : valeur du sémaphore utilisé avec SETVAL.
‣ arg.array : Adresse tableau des valeurs des sémaphores utilisé
avec SETALL.
- 76 -
7.4.4 Opérations sur un ensemble de sémaphores
La primitive semop() permet d’exécuter des opérations sur un groupe de
1 à n sémaphores de l'ensemble. Ce groupe d'opérations sera atomique,
c'est à dire qu'il sera exécuté sur tous les sémaphores du groupe ou sur
aucun.
int semop (int sem_id, struct sembuf *operation, unsigned int nb_op);
❖ sembuf.sem_op = 0 :
Si compteur du sémaphore(sem.semval) n’est pas égal à zéro,
- Mettre le processus en attente jusqu’à ce que le compteur du
sémaphore soit égal à zéro(sem.semval=0).
79 -
✓ Attribut Sem_flg :
‣ En général, on utilise la valeur 0(sem_flag=0);
‣ SEM_UNDO : Restituer l’état initial après une fin anormale d’un
processus.
Le système sauvegarde toutes les opérations effectuées par chacun
des processus sur le sémaphore et en cas de terminaison anormale
d’un processus, le système exécute les opérations inverses de ce
processus sur ce sémaphore.
‣ IPC_NOWAIT : l’opération ne sera pas bloquante même si la valeur
du champ sembuf.sem_op est négative ou nulle.
80 -
7.4.5 Destruction d’un sémaphore
La fonction semctl() avec la ‘commande IPC_RMID’ permet de
supprimer un ensemble de sémaphores :
int semctl (int idf_sem, int num_sem, int commande, arg);
- 81 -
7.4.6 Exemple : Sémaphores svide et splein initialisés à 0 et 10
#define splein 0 /* Numéro du sémaphore splein */
#define svide 1 /* Numéro du sémaphore svide */
/* Préparation des opérations P et V */
struct sembuf Psvide = {svide, -1, 0}; /* P sur svide */
struct sembuf Vsvide = {svide, 1, 0}; /* V sur svide */
struct sembuf Psplein = {splein, -1, 0}; /* P sur splein */
struct sembuf Vsplein = {splein, 1, 0}; /* V sur splein */
int sem; /* Identificateur des sémaphores */
- 82 -
int main()
{ union semun { int val; struct semid_ds *buf; unsigned short *array;
} svideinit, spleininit;
/* Création d'un tableau de 2 sémaphores splein et svide*/
sem = semget(IPC_PRIVATE, 2, IPC_CREAT|0666);
if(sem == -1) { printf("\nErreur de création des semaphore"); exit(1);}
#define indexfichier 0
#define indexnl 1
#define sf 0
#define sfifo 1
#define mutex 2
- 85 -
int memp; /* Idf du seg de memoire partagee fichier */
int sem; /* Idenfificateur des semaphores sf, sfifo et
mutex */
- 86 -
void redacteur(void)
{ int pid; int *f; int *fichier;
pid=getpid();
printf("\n=== Début de la procédure rédacteur : %d ===\n",pid);
/* Attachement du segment */
f =(int *)shmat(memp,0,0);
if(f==NULL){ printf("\nErreur: memoire partagée non attachee");exit(1);}
fichier=f+indexfichier;
/* Demande d’écriture */
semop(sem, &Psfifo,1); /* p(sfifo)*/
semop(sem, &Psf,1); /* p(sf)*/
semop(sem, &Vsfifo,1); /* v(sfifo)*/
*fichier=pid; /* Ecrire sur le fichier */
printf("\n** Le rédacteur %d a écrit sur le fichier:%d **", pid, *fichier);
sleep(2); /* Attendre avant de libérer le fichier */
/* fin d’écriture */
semop(sem, &Vsf,1); /* v(sf)*/
/* Détachement du segment */
shmdt(f);
exit(0); } - 87 -
void lecteur(void)
{ int i; int a; int *f; int *fichier; int *nl; int pid;
pid=getpid(); printf("\n=== Début de la procédure lecteur %d ===\n",pid);
/* Attachement du segment */
f =(int *) shmat(memp, 0, 0);
if(f==NULL){ printf("\nErreur:mémoire partagée non attachée"); exit(0);};
fichier=f+indexfichier;
nl=f+indexnl; /* adresse de la variable nl dans la mémoire partagée*/
/* demande de lecture */
semop(sem, &Psfifo,1); /* P(sfifo) */
semop(sem, &Pmutex,1); /* P(mutex) */
*nl=*nl + 1;
if((*nl)==1) semop(sem, &Psf,1); /* P(sf) */
semop(sem, &Vmutex,1); /* V(mutex) */
semop(sem, &Vsfifo,1); /* V(sfifo)*/
/* lire sur le fichier */
a=*fichier;
printf("\n*** Le lecteur %d lit le fichier : valeur lue=%d ***",pid,a);
sleep(2); /* Attendre avant de liberer */
- 88 -
/* fin de lecture */
semop(sem, &Pmutex,1); /* P(mutex)*/
*nl=*nl-1;
if((*nl)==0) i=semop(sem, &Vsf,1); /* V(sf)*/
semop(sem, &Vmutex,1); /* V(mutex)*/
/* Détachement du segment */
shmdt(f);
exit(2);
}
- 89 -
int main (void)
{ int i; int p; int *f; int *fichier; int *nl;
union semun{ /* préparer les structures pour initialiser les sémaphores */
int val;
struct semid_ds *buf;
unsigned short *array;
} sfinit, sfifoinit, smutexinit;
/* Création d'un segment de mémoire partagée contenant 2 entiers */
memp = shmget(IPC_PRIVATE, 2*sizeof(int), IPC_CREAT|IPC_EXCL|0660);
if(memp==-1){printf("\nErreur de création de la mém partagée"); exit(1);}
/* Attachement du segment de mémoire partagée pour initiliser nl*/
f=(int *)shmat(memp,0,0);
if(f==NULL){printf("\n Erreur: mémoire partagée non attachée");exit(0);}
fichier=f+indexfichier;
*fichier=-1000;
/* Initialisation de nl à 0; */
nl=f+indexnl;
*nl=0;
/* Détachement du segment de mémoire partagée*/
shmdt(f); - 90 -
/* Création d'un tableau de 3 semaphores sf, sfifo et mutex*/
sem = semget(IPC_PRIVATE, 3, IPC_CREAT|IPC_EXCL|0660);
if(sem == -1) { printf("\nErreur de création des sémaphore"); exit(2);}
/* Initialisation des sémaphores */
sfinit.val = 1; semctl(sem, sf, SETVAL, sfinit);
/*semctl(sem, sf, SETVAL, 1);*/
semctl(sem, sfifo, SETVAL, 1);
semctl(sem, mutex, SETVAL, 1);
/* création de 10 processus : lecteurs et rédacteurs */
for(i=0; i<10; ++i){
p=fork();
if(p == -1){ printf("\nErreur de création de processus"); exit(5);}
if(p == 0) {
if(getpid()%3==0)
redacteur(); /* c'est un redacteur */
else
lecteur(); /* c'est un lecteur */
}
sleep(2);
} - 91 -
/* Attendre la terminaison des fils */
while( (p = wait(NULL))!=-1 ) printf("\n Fils %d termine", p);
- 92 -
• Initialisation d’un ensemble de sémaphores avec SETALL
• Dans l’exemple précèdent, l’ensemble est composé de trois sémaphores :
sf, sfifo et smutex.
Les trois sémaphore sont initialisés à 1.
• Soit sinit le tableau qui contient les valeurs initiales de ces 3 sémaphores.
unsigned short int sinit[3]={1,1,1};
union semun{
int val;
struct semid_ds *buf;
unsigned short *array;
} arg;
- 93 -