3LMD - SEII - Chapitre - 3 - Communication
3LMD - SEII - Chapitre - 3 - Communication
3LMD - SEII - Chapitre - 3 - Communication
La communication est un outil important qui permet de faire évoluer l’ensemble des processus
dans un système.
Il existe plusieurs stratégies pour réaliser cette communication, nous citons :
- Variables partagées (modèles : producteur/ consommateur)
- Échange de messages (modèles : producteur/consommateur, client/serveur, Boite aux
lettres)
1. Communication par variables partagées (modèles : producteur/ consommateur) :
Un modèle de communication entre processus avec partage de zone commune (tampon) est
le modèle producteur‐consommateur. Ce modèle a été décrit en détaille dans le chapitre 3
sur la synchronisation.
Répéter
produire_objet (&objet) /* produire un nouvel objet */
receive (consommateur , &m) /* attendre un message vide */
faire_message (&m , objet) /* construire un message à envoyer */
send (consommateur , &m) /* envoyer le message */
Jusqu’à faux
consommateur
send (producteur , &m) /* envoyer un messages vides */
Répéter
receive (producteur , &m) /* attendre un message */
retirer_objet (&m , &objet) /* retirer l'objet du message */
consommer_objet (objet)
send (producteur , &m) /* renvoyer une réponse vide */
Jusqu’à faux
Page
40
b. Communication indirecte :
Les messages sont envoyés et reçus à travers des boites aux lettres (BAL). Ces dernières
peuvent être vues comme des objets où l’on peut déposer et retirer des messages.
Chaque boite aux lettres dispose d’un identificateur unique. Les processus peuvent alors
communiquer à travers plusieurs boites aux lettres.
Les primitives Send et Receive sont définies comme suit :
- Send(A, &message) : envoyer le « message » à la BAL A avec ou sans blocage si
pleine.
- Receive (A , &message) : recevoir le « message » de la BAL A avec ou sans
blocage si vide.
Deux autres primitives sont nécessaires :
- BAL = CreationBAL(nom) : retourne le descripteur de la BAL crée.
- BAL = RelierBAL(nom) : recherche la BAL et retourne son descripteur.
Page
41
Exemple d’utilisation des tubes ordinaires (fichier pipe.c):
# include <stdio.h>
# include <unistd.h>
int tube[2];
char buf[20];
main()
{ pipe(tube);
if (fork())
{ /* pere */
close (tube[0]);
write (tube[1], "bonjour", 8);
}
else
{ /* fils */
close (tube[1]);
read (tube[0], buf, 8);
printf ("%s bien recu \n", buf);
}
}
Remarque :
- Si un processus ouvre un tube nommé en lecture (resp. écriture) alors qu’il n’y a
aucun processus qui ait fait une ouverture en écriture (resp. lecture) alors, le
processus sera bloqué jusqu’à ce qu’un processus effectue une ouverture en
écriture (resp. en lecture).
- Attention au situation d’interblocage :
Page
43
1. Les segments de mémoire partagée : Les segments de mémoire partagée
permettent à deux processus distincts de partager physiquement des données. Le
partage est réalisé par l'espace d'adressage de chacun des processus, dont
une zone pointe vers un segment de mémoire partagée. Lorsqu'un processus
modifie la mémoire, tous les autres processus voient la modification.
Page
44
- rend 0 en cas de succès et ‐1 sinon.
Suppression d’un segment :
int shmctl(int shmid, int cmd, shmid_ds *buf);
- cmd = IPC_RMID
- buf= NULL.
Page
45
Si l'appel se passe bien, msgget renvoie un identifiant de file de message
crée. Si la file de message existe déjà, les permissions d'accès sont vérifiées.
Émission des messages :
int msgsnd(int msgid, struct msgbuf *msg,int taille,int flags);
où : struct msgbuf { /* définie dans sys/msg.h */
long mtype; /* type du message */
char mtext[1]; /* texte du message */
};
Avec possibilité de redéfinir cette structure en fonction de ses besoins.
Cette primitive permet à un processus d’envoyer le message, msg, dans la file de
message spécifié par l’id msgid. Elle retourne 0 en cas de succès et ‐1 sinon.
Remarque : La primitive msgsnd est une fonction bloquante i.e. si la file de
message est plein, le processus est suspendu jusqu’à extraction de messages
de la file ou bien suppression du système de la file (retourne ‐1). Si
IPC_NOWAIT → flags, et que la file est pleine, la fonction devient non
bloquante. Donc, le message ne sera pas envoyé et le processus peut
reprendre la main immédiatement.
Réception des messages :
int msgrcv(int msgid, struct msgbuf *msg, int taille, long
type, int flags);
La primitive msgrcv permet de retirer un message de la file en fonction de son type.
Comme pour msgsnd, IPC_NOWAIT rend l’appel non bloquant.
- type = 0 : le premier message est lu
- type>0 : le premier message de type msgtype est lu
- type<0 : le premier message dont le type est inférieur ou égal à
|msgtyp| est lu
Suppression des files de messages :
int msgctl(int msgid, int cmd, msqid_ds *buf);
- cmd = IPC_RMID.
- Buf = NULL.
Exemple (fichier shm.c):
#include <sys/ipc.h>
#include <sys/msg.h>
…
int msg_id; struct msqid_ds *buf;
struct message {
long type;
char texte[128];
} msg;
…
msg_id = msgget (IPC_PRIVATE, IPC_CREAT);
…
msg.type = 1;
for ( ; ; ) {
printf ( "Entrer le texte a emettre \n");
scanf("%s",msg.texte);
msgsnd(msg_id , &msg , sizeof( struct message ) , 0);
…
}
Page
46
3. Les sémaphores :
Tous les problèmes de synchronisation ne sont pas solubles avec les
sémaphores simples de Djiskstra, tels qu'ils ont été décrits précédemment.
Exemple : la demande de m ressources différentes, dans un ensemble de n ressources
(m <= n).
Soit les n sémaphores S1, S2, ..., Sn permettant de bloquer les n ressources. Si
P1 demande R1, R2, R3 et R4 et P2 demande R2, R3, R4 et R5 alors on a :
P1 -> P(S1), P(S2), P(S3), P(S4) et
P2 -> P(S3), P(S4), P(S5), P(S2)
On a un risque d'interblocage.
Solution : Si les 4 opérations P étaient atomiques, on éviterait les interblocages
(deadlock) : P1 -> P(S1,S2,S3,S4) et
P2 -> P(S3,S4,S5,S2)
Idée : ensemble de sémaphores.
Création ou recherche de l’identifiant d’un ens. de sémaphores :
int sem_id = semget(key_t cle, int nsems, int flags);
- nsem: nombre de sémaphores à créer dans le groupe.
Cette fonction renvoie l'id. de l’ens. des sémaphores ds la table en cas de
succès (> 0) ‐1 sinon.
Initialisation des sémaphores :
int semctl (int semid, int semnum, int cmd, union semun arg);
- semnum : numéro du sémaphore choisi dans le groupe (0 pour le premier).
- cmd : type d'opération à effectuer sur le sémaphore, par exemple SETVAL pour
initialiser le sémaphore à la valeur contenue dans "arg".
- arg : sert à passer des arguments aux commandes exécutées par "cmd".
Opérations sur les sémaphores :
int semop(int semid, struct sembuf *sops, unsigned nsops);
structure d’une operation:
struct sembuf {
ushort sem_num; /* N° du semaphore*/
short sem_op; /* opération sur le sémaphore */
shrot sem_flag; /* options */
};
- sops : tableau de structures qui contient la liste des opérations.
Cette fonction retourne 0 en cas de succès et ‐1 sinon.
L'opération semop est en principe bloquante, i.e. le processus est mis en
sommeil si l'une des opérations de l'ensemble ne peut être effectuée.
Dans ce cas, aucune opération de l'ensemble n'est réalisée.
Une opération élémentaire comporte un numéro de sémaphore et
une opération qui peut avoir trois valeurs :
une sem_op > 0, pour une opération Vsem_op, (semval = semval + sem_op)
Tous les processus en attente d'une augmentation du sémaphore sont reveilles.
une sem_op = 0, teste si le sémaphore a la valeur 0. Si ce n'est pas le cas, le processus est mis
en attente de la mise à zéro du sémaphore.
une sem_op < 0, pour une opération Psem_op (semval = semval - |sem_op|)
Si le résultat est :
nul: tous les processus en attente de cet événement sont réveillés
négatif: le processus est mis en attente d'une augmentation du sémaphore
Page
47
Exemple (semEM.c) :
#include <sys/ipc.h>
#include <sys/sem.h>
#define SEM_EXCL_MUT 0
#define NB_SEM 1
int FLAGS = IPC_CREAT; int sem_id;
struct sembuf op;
main ( )
{
sem_id = semget (IPC_PRIVATE, NB_SEM, FLAGS );
semctl(sem_id, SEM_EXCL_MUT, SETVAL, 1);
…
P(SEM_EXCL_MUT);
/* Section Critique */
V(SEM_EXCL_MUT);
…
semctl(sem_id, SEM_EXCL_MUT, IPC_RMID, 0);
}
Page
48
- Communication dans les langages évolués (CSP, ADA, JAVA..)
Bibliographie :
[1] J‐L. Peterson, F. Silbershartz, P. B.Galivin « Operating systems concepts » Fourth Edition.
[5] Andrew S. Tanenbaum, “Moderrn operating systems,” Second Edition Prentice Hall.
[6] Maurice J.Bach, traduit par G.Feallah, “Conception du système UNIX, » Masson
Page
49