Introduction
Il n'est pas forcément facile de trouver un mode d'emploi clair des sémaphores System V, surtout en français. Cette astuce ne se veut pas exhaustive, mais on va quand même essayer de débroussailler un peu le chemin et clouer quelques panneaux pour savoir où aller.
Sommaire:
Au commencement: la création d'une clé
Nous allons utiliser une fonctionnalité gérée selon la mode des IPC (Inter Processus Communication).
Et tout objet IPC est créé ou retrouvé à partir d'une clé unique. Cette clé est un entier et pour la choisir vous avez deux manières:
- Au pif
- En utilisant une fonction qui crée une clé à partir d'un chemin vers un fichier
Si vous choisissez votre clé au hasard, vous risquez d'entrer en conflit avec un autre programme qui a voulu utiliser la même.
L'idéal, c'est plutôt de créer une clé générée à partir d'un nom de fichier, en l'occurrence le nom de votre programme.
Pour ça, on va utiliser deux choses, d'abord la fonction
ftok dont le prototype est le suivant:
#include <sys/types.h>
#include <sys/ipc.h>
key_t ftok (char *pathname, char proj )
Celle-ci va nous permettre de créer notre clé à partir de deux choses:
- pathname: C'est le chemin vers le fichier qui sera choisi pour générer la clé.
- proj: Une valeur qu'il vous revient de définir, mettez le caractère que vous voulez. Ça peut vous permettre de définir plusieurs clés pour un même fichier.
Cette fonction retourne un key_t, synonyme d'un entier.
Maintenant, la manière la plus simple pour connaître le nom de fichier de votre programme, c'est de le prendre dans les arguments du main. Si votre liste d'arguments s'appelle argv, alors le nom de votre programme se trouve dans argv[0].
Exemple
# include <sys/types.h>
# include <sys/ipc.h>
#define ID_PROJET 'P'
int main(int argc, char **argv)
{
key_t clef;
clef = ftok(argv[0], ID_PROJET);
return 0;
}
Création du/des sémaphore(s)
Maintenant que nous avons notre clé, nous allons pouvoir nous en servir pour créer notre sémaphore.
C'est la fonction
semget qui nous intéresse ici, voici son prototype:
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>
int semget ( key_t key, int nsems, int semflg )
Explication des paramètres:
- key: La clé que nous venons de créer
- nsems: Le nombre de sémaphores que nous voulons créer
- semflg: Les permissions et les paramètres lors de la création de notre sémaphore
Il va falloir un peu plus de précisions sur smflg. Cette variable peut prendre plusieurs valeurs combinées par le biais de l'opérateur | qui est l'opérateur "ou" binaire.
Il y a deux parties à prendre en compte: les paramètres de création du sémaphore et les permissions sur ce sémaphore.
Les paramètres de création sont IPC_CREAT (indique que l'on veut créer un sémaphore) que l'on peut éventuellement combiner avec IPC_EXCL (indique que la fonction doit échouer si le sémaphore associé à la clé existe déjà). Concernant les permissions, le codage est le même que pour la commande chmod. Par exemple 0666 donnera les permissions de lecture/écriture pour tout le monde sur ce(s) sémaphore(s). Notez la présence d'un 0 au début du nombre pour dire au compilateur que 666 est à prendre en temps que nombre codé en octal.
Si vous ne voulez pas vous prendre la tête, choisissez 0666, ça fonctionnera toujours, mais si vous développez une véritable application, pensez à adapter ces permissions pour la sécurité.
La fonction semget retourne un identifiant vers votre (ou vos) sémaphore(s). C'est à partir de cet identifiant que vous pourrez manipuler votre sémaphore par la suite.
Exemple
Création d'un sémaphore ; échoue si le sémaphore associé à la clé existe déjà:
# include<sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>
#define ID_PROJET 'P'
int main(int argc, char **argv)
{
key_t clef;
int semid;
clef = ftok(argv[0], ID_PROJET);
semid = semget(clef, 1, IPC_CREAT | IPC_EXCL | 0666);
return 0;
}
Initialisation du sémaphore
A présent que nous avons créé notre sémaphore (on en crée un seul pour faire simple), nous allons devoir l'initialiser à la valeur que l'on souhaite. Mettons que l'on veuille que notre sémaphore soit un mutex (donc ne pouvant prendre que les valeurs 1 ou inférieur), nous allons lui mettre la valeur 1.
Pour cela, on utilise la fonction
semctl dont le prototype est le suivant:
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>
int semctl ( int semid, int semno, int cmd, union semun arg )
- semid est l'identifiant de notre sémaphore que nous venons de créer
- semno est le énième sémaphore créé qui nous intéresse. Attention, ça commence à zéro, et comme on en a créé qu'un seul, celui qui nous intéresse est le zéro.
- cmd est la commande à appliquer à notre sémaphore ; ici, celle qui nous intéresse est SET_VAL pour donner une valeur à notre sémaphore.
- arg est un paramètre dont le type a une interprétation différente selon la commande envoyée. Comme nous avons choisi SET_VAL, ici arg sera de type int et représentera la valeur que l'on veut affecter à notre sémaphore.
Exemple
Initialisation de notre sémaphore à 1
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>
#define ID_PROJET 'P'
int main(int argc, char **argv)
{
key_t clef;
int semid;
clef = ftok(argv[0], ID_PROJET);
semid = semget(clef, 1, IPC_CREAT | IPC_EXCL | 0666);
semctl(semid, 0, SET_VAL, 1);
return 0;
}
Equivalent du P() ou down()
Maintenant, nous voulons faire un P() (ou down() ) sur notre sémaphore, ce qui signifie que nous voulons le décrémenter. En l'occurrence, comme c'est un mutex, cela signifie lui dire que l'on entre dans une section critique.
Ça va peut-être vous paraître étrange, mais les opérations sur les sémaphores doivent être modélisées dans une structure.
Voici cette structure:
struct sembuf{
short sem_num;
short sem_op;
short sem_flg;
};
Comme décrit
ici, sem_num est le numéro de votre sémaphore (0 pour nous), sem_op est l'opération à réaliser (-1 pour décrémenter et 1 pour incrémenter) et sem_flg contient les paramètres de l'opération. Ce dernier n'est pas important pour nous, on va le mettre à zéro.
On va donc initialiser notre structure ainsi pour un P():
struct sembuf op;
op.sem_num = O; //Numéro de notre sémaphore: le premier et le seul
op.sem_op = -1; //Pour un P() on décrémente
op.sem_flg = 0; //On ne s'en occupe pas
Pour exécuter notre opération, on utilisera la fonction
semop. On n'hésite pas à l'exhiber en public:
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>
int semop ( int semid, struct sembuf *sops, unsigned nsops )
Les paramètres:
- semid: l'identifiant de votre sémaphore, comme d'habitude. Celui qui vous a été donné par semget.
- sops: l'adresse de votre structure sembuf
- nsops: le nombre d'opérations à effectuer. Ici nous n'avons qu'une seule opération à effectuer, donc on mettra 1. Si vous en avez plusieurs, il vous faudra passer un tableau de structures sembuf dans le paramètre sops.
Exemple
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>
#define ID_PROJET 'P'
int main(int argc, char **argv)
{
key_t clef;
int semid;
sembuf op;
clef = ftok(argv[0], ID_PROJET);
semid = semget(clef, 1, IPC_CREAT | IPC_EXCL | 0666);
semctl(semid, 0, SET_VAL, 1);
op.sem_num = O; //Numéro de notre sémaphore: le premier et le seul
op.sem_op = -1; //Pour un P() on décrémente
op.sem_flg = 0; //On s'en occupe pas
semop(semid, &op, 1);
//Zone critique
//.......
return 0;
}
Equivalent du V() ou up()
Le V() incrémente le mutex. Il est utilisé pour libérer le mutex lorsque l'on sort d'une section critique.
Pour l'utiliser, rien de plus simple: c'est comme pour un P() sauf qu'il faut mettre 1 dans op.sem_op.
Destruction du sémaphore
Comme toujours, lorsqu'on utilise une ressource offerte gracieusement par le système d'exploitation, il faut la libérer ensuite.
Pour cela, on utilise la fonction semctl avec semid comme identifiant de notre sémaphore et IPC_RMID dans cmd. Les autres arguments peuvent être réglés avec la valeur que vous voulez, il ne seront pas pris en compte.
Ici, on fera donc:
semctl(semid, 0, IPC_RMID, 0);
NOTE: Si vous aviez plusieurs sémaphores attachés à ce semid, ils seront tous détruits.
NOTE: Si vous omettez cette étape de destruction, vos sémaphores existeront encore après la fin de votre processus. Vous pourrez néamoins les effacer avec la commande ipcrm.
Bilan
Tous les processus qui voudront utiliser la même section critique devront utiliser le même sémaphore.
Pour retrouver le sémaphore créé par un programme, il suffit d'utiliser ftok avec le chemin vers le programme qui a créé le sémaphore et le même id de projet. Puis, un appel à semget avec le paramètre IPC_CREAT sans IPC_EXCL permettra de retrouver ce sémaphore partagé.
Voici notre code final pour créer un sémaphore mutex et l'utiliser pour entrer dans une section critique:
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>
#define ID_PROJET 'P'
int main(int argc, char **argv)
{
key_t clef;
int semid;
sembuf op;
clef = ftok(argv[0], ID_PROJET); //Obtention d'un clé
semid = semget(clef, 1, IPC_CREAT | IPC_EXCL | 0666); //Obtention d'un identifiant de sémaphore
semctl(semid, 0, SET_VAL, 1); //Initialisation du sémapore à 1
op.sem_num = O; //Numéro de notre sémaphore: le premier et le seul
op.sem_op = -1; //Pour un P() on décrémente
op.sem_flg = 0; //On ne s'en occupe pas
semop(semid, &op, 1); //Entrée dans la section critique (P() ou down())
//Section critique
op.sem_op = 1; //Pour un V() on incrémente
semop(semid, &op, 1); //Sortie de la section critique (V() ou up())
semctl(semid, 0, IPC_RMID, 0); //Destruction du sémaphore
return 0;
}
Sources et compléments
Lire la suite
Fichier bat de sauvegarde sous Excel avec increment date »
Publié par
kilian -
Dernière mise à jour le 13 novembre 2009 à 14:13 par marlalapocket