C semaphore
Introduction
Les sémaphores permettent de gérer ce que l'on appelle les sections critiques. Il y a des parties de code où l'on souhaite que toutes les instructions soient exécutées en évitant les interblocages un peu comme avec un mutex.
On peut se demander quelle est la différence avec un mutex ?
Un mutex est un mécanisme de verrouillage utilisé pour synchroniser l'accès à une ressource alors qu'un sémaphore est un mécanisme de signalisation utilisé pour sérialiser l'exécution dans une portion de code. Un peu comme si les processus se passer le mot: "J'ai fini, tu peux y aller".
Utilisation
Création
Tout d'abord, il faut créer un objet de type sémaphore:
#include <semaphore.h>
sem_t semaphore;
Initialisation
Une fois l'objet créé, on peut l'initialiser:
#include <semaphore.h>
int sem_init(sem_t *semaphore, int pshared, unsigned int valeur);
- semaphore → pointeur vers le sémaphore à initialiser ;
- pshared → drapeaux qui précise si le sémaphore est utilisé par des threads (valeur 0) ;
- valeur → valeur de départ du sémaphore.
- le code retour varie entre:
- '0' si tout s'est bien passé
- '1' si une erreur survient et errno est positionné
Blocage
Une fois le sémaphore initialisé, on peut demander son blocage avec
#include <semaphore.h>
int sem_wait(sem_t *semaphore);
- semaphore → pointeur vers le sémaphore à bloquer ;
- le code retour varie entre:
- '0' si tout s'est bien passé
- '-1' si une erreur survient et errno est positionné
Cette fonction est bloquante ! |
#include <semaphore.h>
int sem_trywait(sem_t *semaphore);
- semaphore → pointeur vers le sémaphore à bloquer ;
- le code retour varie entre:
- '0' si tout s'est bien passé
- '-1' si une erreur survient et errno est positionné
Cette fonction est non bloquante ! |
#include <semaphore.h>
#include <time.h>
int sem_timedwait(sem_t *semaphore, const struct timespec *abs_timeout);
- semaphore → pointeur vers le sémaphore à bloquer ;
- le code retour varie entre:
- '0' si tout s'est bien passé
- '-1' si une erreur survient et errno est positionné
Cette fonction est non bloquante le temps spécifié ! |
Voici le détail de la structure timespec:
struct timespec {
time_t tv_sec; /* Seconds */
long tv_nsec; /* Nanoseconds [0 .. 999999999] */
};
Relâchement d'un sémaphore
Une fois la section critique passée, on peut relâcher le sémaphore:
#include <semaphore.h>
int sem_post(sem_t *semaphore);
- semaphore → pointeur vers le sémaphore à bloquer ;
- le code retour varie entre:
- '0' si tout s'est bien passé
- '-1' si une erreur survient et errno est positionné
Exemple
Ci-dessous un exemple d'utilisation d'un sémaphore:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/wait.h>
#include <string.h>
#include <pthread.h>
#include <errno.h>
#include <semaphore.h>
#define NB_THREAD 4
#define LIMIT 2
// Création du sémaphore;
sem_t semaphore;
void * job(void * args) {
// Récupération de l'identifiant du thread
int tid = pthread_self();
int i = 0;
while (i < LIMIT) {
// On attend la disponibilité du sémaphore
sem_wait(&semaphore);
// Section critique
printf("Je suis le thread [%i] et je vais dormir 1 seconde\n", tid);
sleep(1);
printf("Je suis le thread [%i] et j'ai fini ma sieste\n", tid);
// On relache le sémaphore
sem_post(&semaphore);
i++;
}
pthread_exit(EXIT_SUCCESS);
}
int main() {
// Création d'un tableau de thread
pthread_t threads[NB_THREAD];
// Initialisation du sémaphore
sem_init(&semaphore, PTHREAD_PROCESS_SHARED, 1);
for (int i = 0; i < NB_THREAD; i++) {
int err;
if ((err = pthread_create(&threads[i], NULL, job, NULL)) != 0) {
printf("Echec de la création du thread: [%s]", strerror(err));
return EXIT_FAILURE;;
}
printf("Création du thread numéro %i\n", i);
}
for (int i = 0; i < NB_THREAD; i++) {
pthread_join(threads[i], NULL);
}
sem_destroy(&semaphore);
return EXIT_SUCCESS;
}
Ce programme donne, par exemple, la sortie suivante:
Création du thread numéro 0 Création du thread numéro 1 Création du thread numéro 2 Création du thread numéro 3 Je suis le thread [-1171347712] et je vais dormir 1 seconde Je suis le thread [-1171347712] et j'ai fini ma sieste Je suis le thread [-1171347712] et je vais dormir 1 seconde Je suis le thread [-1171347712] et j'ai fini ma sieste Je suis le thread [-1192327424] et je vais dormir 1 seconde Je suis le thread [-1192327424] et j'ai fini ma sieste Je suis le thread [-1192327424] et je vais dormir 1 seconde Je suis le thread [-1192327424] et j'ai fini ma sieste Je suis le thread [-1181837568] et je vais dormir 1 seconde Je suis le thread [-1181837568] et j'ai fini ma sieste Je suis le thread [-1181837568] et je vais dormir 1 seconde Je suis le thread [-1181837568] et j'ai fini ma sieste Je suis le thread [-1160857856] et je vais dormir 1 seconde Je suis le thread [-1160857856] et j'ai fini ma sieste Je suis le thread [-1160857856] et je vais dormir 1 seconde Je suis le thread [-1160857856] et j'ai fini ma sieste
On voit bien les threads exécuter la section critique les uns après les autres !