Les sémaphores

 

Les primitives IPC pour les sémaphores permettent la gestion des accès concurrents à une ressource.

Le concept des sémaphores date de 1965 par Edsger Dijkstra (Néerlandais), d'où les termes suivants qui seront utilisés:

P() pour Proberen (tester) ou down ou wait en anglais

V() pour Verhogen (incrémenter) ou up ou signal en anglais


V() : s = s + 1
P() : si s > 0 alors s = s-1 sinon "wait"

Il s'agit d'un principe de jetons. s jetons sont disponibles:

Un processus déclenche P() pour savoir s'il peut commencer à travailler sur une ressource par exemple. Si s > 0, alors il prend un jeton s et peut travailler. Sinon, s = 0 donc plus de jeton disponible, le processus attend qu'au moins un jeton soit de nouveau disponible et donc que s redevienne positif. En attendant, il ne fait rien !

Lorsqu'un processus a terminé son travail, il libère le jeton en effectuant v()...

 

Image non trouvée !Cette solution ne va pas résoudre tous les problèmes de synchronisation des processus. Ou plutôt d'autres problèmes peuvent se produire comme l'inter-bloquage.

 

Obtenir l'identifiant d'un ensemble de sémaphores

 

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

int semget (key_t key, int nsems, int semflg);

En entrée: key, il s'agit d'une information permettant à différents processus de communiquer ensembles. Ici, la communication passant par la gestion d'un ticket permettant d'accéder à une ressource partagée entre les processus.

La clef pourra être positionnée à IPC_PRIVATE

nsems: nombre de sémaphores

semflg: composé de flags et des droits d'accès (ex. courant: 0666 en octal) qui peuvent être combinaient entre eux par un ou logique (|):

IPC_CREAT Créer un sémaphore s'il n'existe pas déjà. Sinon réutilisation de celui existant (suivant les droits).

IPC_EXCL S'assurer que l'on vient bien créer le sémaphore. A utiliser combiner avec IPC_CREAT. semget va donc échouer si l'ensemble des sémaphores existent déjà.

 

En sortie:

identifiant sur l'ensemble des sémaphores associé à la clef unique key ou -1 si erreur. Dans ce dernier cas, errno peut être positionné à:

Code Désignation
EACCES L'ensemble des sémaphores associé à key existe, mais le processus n'a aucun droit d'accès sur lui et n'a pas la capacité CAP_IPC_OWNER.
EEXIST L'ensemble des sémaphore associés à key existe alors que les flags IPC_CREAT et IPC_EXCL sont positionnés
EINVAL nsems est inférieur à zéro ou supérieur à la limite sur le nombre de sémaphores par ensemble, (SEMMSL), ou l'ensemble des sémaphores identifié par key existe déjà, et nsems est plus grand que le nombre de sémaphores par ensemble..
ENOENT Aucun ensemble de sémaphores associé a key n'existe et l'argument semflg ne précise pas IPC_CREAT.
ENOMEM Pas assez de mémoire pour créer les structures nécessaires.
ENOSPC Le nombre maximal d'ensemble de sémaphores sur le système (SEMMNI) est atteint, ou le nombre maximal de sémaphores sur le système est atteint (SEMMNS).

Image non trouvée ! Il faut considérer que semget n'initialise pas les valeurs des sémaphores à 0 !

semid = semget(clef, 1, IPC_CREAT | IPC_EXCL | 0666);
semctl(semid, 0, SET_VAL, 1);

 

P() ou V() sur un sémaphore

pour effectuer un p() ou un v() sur un sémaphore, il faudra passer par une structure

struct sembuf{

short sem_num;
short sem_op;
short sem_flg;

};

ou sem_num est le numéro du sémaphore à tester ou incrémenter dans l'ensemble de nos sémaphores.

sem_op et l'opération à effectuer: Généralement -1 pour p(), 1 pour v()

  • Supérieure à zéro : V(), la valeur est ajoutée au sémaphore traité. Tous les processus qui attentent une augmentation du sémaphores sont réveillés.
  • Egale à zéro : Teste si le sémaphore à la valeur 0. Si ce n'est pas le cas, le processus est mis en attente de la mise à zéro du sémaphore.
  • Inférieur à zéro : P(), Si la valeur du sémaphore est >= à la valeur absolue, elle est retranchée du sémaphore traité. Sinon, si la valeur du sémaphore est < à la valeur absolue, le processus est mis en attente d'une augmentation du sémaphore.

sem_flg un flag que l'on laissera à 0.

 

Pour effectivement modifier un ou plusieurs sémaphores de l'ensemble des sémaphores, vous utiliserez

int semop(semid,oplist,nbop)

En entrée:

semid est l'identifiant de l'ensemble des sémaphores.

oplist est un tableau sur le ou les sembuf indiquant le ou les sémaphores à modifier.

nbop est le nombre d'éléments de oplist

 

Destruction/maj sémaphore

Tout passe par:

union semun {
int val;
struct semid_ds *buf;
ushort *array
}

int semctl(int semid, int semnum, int cmd, semun arg);

 

Pour supprimer un ensemble de sémaphores

semctl(semid, 0, IPC_RMID, 0);


Image non trouvée ! Si vous aviez plusieurs sémaphores attachés à ce semid, ils seront tous détruits. Si vous oubliez de faire le ménage en libérant les sémaphores, vous pouvez le faire avec la commandes ipcrm du shell.

 

Pour modifier un sémaphore

cmd à SETVAL : affecte la valeur arg.val à semnum

union semun arg et arg.val = valeur

semctl(semid,0,SETVAL,arg);

Avec 0 le sémaphore à modifier

 

Pour récupérer des informations sur un sémaphore:

cmd à GETVAL: renvoie la valeur semval du sémaphore semnum