next up previous contents
Next: Contrôle des ressources IPC Up: Les Inter Process Communication Previous: Exemple d'accès à une   Contents

Implémentation

Sous UNIX, on accède à un ensemble de sémaphores dont chaque élément peut prendre n'importe quelle valeur et être modifié par -1 ou +1. On utilise souvent un ensemble de 1 sémaphore (pour raisons de complexité).

ATTENTION : le sémaphore est un indicateur de disponibilité. Rien n'empêche d'accéder à la ressource en outrepassant l'avertissement donné par le sémaphore.

Considérons le cas d'un sémaphore de l'ensemble qui protège la ressource $R$. Pour que $R$ soit utilisable, il faut commencer par initialiser le sémaphore à sa valeur maximale. L'initialisation des sémaphores fait partie des opérations effectuées par semctl(), celle-ci travaillant directement sur les structures associées à l'ensemble de sémaphores.

Chaque processus manipulant un sémaphore possède une copie semadj du nombre de points pris au sémaphore. Cette copie sert à remettre à jour le sémaphore si le processus est tué sans avoir libéré la ressource.

La fonction int semget(key_t key, int nsems, int semflg) crée un ensemble de sémaphores associé à la clef key ou -1 en cas d'erreur. semflg définit les droits d'accès6.1 ainsi que le mode de création (IPC_CREAT ou IPC_EXCL). Un nouvel ensemble de sémaphores est crée si key vaut IPC_PRIVATE ou si IPC_CREAT est positionné et que l'ensemble n'existe pas déjà. semget() retourne une erreur si un ensemble est déjà associé à une clef et que IPC_CREAT et IPC_EXCL sont positionnés.

La fonction int semctl(int semid, int semnum, int cmd, union semun arg) permet le contrôle des données associées à l'ensemble de sémaphores identifié par semid. Le paramètre cmd permet de spécifier l'opération effectuée. Si cette dernière concerne un sémaphore particulier, semnum représente le numéro du sémaphore visé. arg est une structure à champ variable permettant de manipuler le type d'objet souhaité, selon l'opération cmd effectuée.

La variable arg est définie comme ayant la structure semun :


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

Les valeurs (et donc les opérations) pouvant être prises par cmd sont :

[linewidth=1pt,fillstyle=solid,shadow=true](-0.5,0)(17.5,-12)

L'exemple suivant montre comment créer un ensemble de 1 sémaphore (!) associé à la cle 10. La valeur du sémaphore est initialisée à 1 :


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

void main(int arc, char * argv[])
{
   int semid;
   union semun {
      int val;
      struct semid_ds *buf;
      ushort array[1];
   }   arg;

   if ((semid=semget((key_t)10,1,IPC_CREAT+0777))==-1) {
      perror("semget");
      exit(1); }
   printf("%s%d","Id semaphore recupere=",semid);
   argv.val=1;
   if (semctl(semid,0,SETVAL,arg)==-1)   {
      perror("semctl");
      exit(1);
   }
   printf("Semaphore initialise");
}

La fonction int semop(int semid, struct sembuf *sops, unsigned nsops) permet de réaliser un ensemble d'opérations sur nsops sémaphores de l'ensemble identifié par semid. semop est une opération dite ``atomique'' dans le sens où aucune interruption n'est possible durant la réalisation des opérations spécifiées dans sops[]. Pour chaque sémaphore concerné par l'appel semop, l'opération à exécuter semop et le numéro de sémaphore correspondant sem_num sont précisés dans la structure sembuf. L'ensemble des nsops structures représentant un tableau pointé par sops.

Selon les valeurs de sem_op et sem_flg, le fonctionnement est le suivant :

[linewidth=1pt,fillstyle=solid,shadow=true](-0.5,0)(17.5,-19)

L'exemple ci-dessous montre comment utiliser un sémaphore pour contrôler l'accès exclusif à une ressource. Le processus commence par récupérer l'identificateur de l'ensemble puis essaie de diminuer la valeur du sémaphore. S'il obtient satisfaction, il s'endort pendant 10 secondes et restitue sa valeur au sémaphore. Il indique à chaque fois son numéro de processus. La fonction semcall prend en charge l'opération à effectuer sur le sémaphore.


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

int semid;

void semcall(int op)
{
   struct sembuf sb;
   
   sb.sem_num=0;
   sb.sem_op=op;
   sb.sem_flg=SEM_UNDO;
   if (semop(semid,&sb,1)==-1) {
      perror("semop");
      exit(1);
   }
}

void main(int arc, char * argv[])
{
   int pid=getpid();;
   
   if ((semid=semget((key_t)10,1,0))==-1) {
      perror("semget");
      exit(1); }

   printf("Semaphore %d recupere\n",semid);
   printf("Demande d'acces par %d\n",pid);
   semcall(-1);
   printf("Acces accorde %d\n",pid);
   sleep(10);
   semcall(1);
   printf("Acces libere par %d\n",pid);
}


next up previous contents
Next: Contrôle des ressources IPC Up: Les Inter Process Communication Previous: Exemple d'accès à une   Contents
Arnaud Revel
2001-11-26