Les sémaphores

 

 

Les sémaphores permettent de limiter le nombre d'accès à une ressource. Les sémaphores sont accessibles entre threads, et même entre applications. Ceci étant possible car l'identificateur du sémaphore est un nom.

Le principe est similaire au mutex, mais au lieu de n'autoriser qu'un thread à une ressource, vous pourrez en autoriser n au maximum:

La première chose à faire est de créer un sémaphore (si le sémaphore existe déjà, il s'agira simplement d'une ouverture):

HANDLE CreateSemaphore(
LPSECURITY_ATTRIBUTES lpSemaphoreAttributes,
LONG lInitialCount,
LONG lMaximumCount,
LPCTSTR lpName
);

avec:

lpSemaphoreAttributes Pointeur sur une structure du type SECURITY_ATTRIBUTES pour déterminer la manière d'hériter le handle dans un processus fils. Si la valeur est NULL, le handle ne sera pas hérité.

lInitialCount : Valeur initial du compteur de sémaphore doit être compris entre [0,lMaximumCount]
lMaximumCount : Valeur maximum du compteur de sémaphore
lpName : Nom du sémaphore, qui doit se terminer par NULL, mais comme le mutex, peut aussi commencer par NULL...

On peut préfixer le nom par Global\ ou local\ pour indiquer que l'objet est global ou uniquement dans une session (jamais essayé...)

Si le nom est identique à un objet évenement, semaphore, waitable timer, job, ou file-mapping, , la création du mutex echoue et GetLastError retourne le code ERROR_INVALID_HANDLE.


Valeur retournée:

Si la fonction n'échoue pas, la valeur retournée est un handle sur un semaphore. Mais il faudra encore tester si nous l'avons créé ou simplement ouvert. Pour cela, il est impératif de tester GetLastError. Si la valeur est ERROR_ALREADY_EXISTS, alors nous ne l'avons pas créé...il y a déjà quelqu'un !

Si la valeur est NULL, c'est qu'il y a un problème.

 

Ouvrir un sémaphore:

HANDLE OpenSemaphore(
DWORD dwDesiredAccess,
BOOL bInheritHandle,
LPCTSTR lpName
);

Alors là, gros copier/coller du mutex:

Les paramètres sont identiques à CreateSemaphore.

La nouveauté vient du champ bInheritHandle qui si à TRUE va permettre l'héritage du handle lors d'un CreateProcess.

Valeur retournée:

NULL si problème. Par exemple semaphore inexistant sera retourné par GetLastError avec le code ERROR_FILE_NOT_FOUND.

Sinon, c'est le handle du semaphore.

 

Et enfin "releaser" le semaphore:cette fonction va nous permettre de modifier la valeur maximum du compteur du semaphore.

BOOL ReleaseSemaphore(
HANDLE hSemaphore,
LONG lReleaseCount,
LPLONG lpPreviousCount
);

Avec lReleaseCount la nouvelle valeur maximum du sémaphore.

Image non trouvée ! Si la valeur courante du compteur est déjà supérieure à la nouvelle valeur, la fonction ne fera rien et retournera FALSE. Autres remarques : on ne peut pas passer une valeur négative pour réduire la valeur maximum du compteur.

Enfin, lpPreviousCount doit pointer sur une variable qui va rececoir l'ancienne valeur maximum du compteur, enfin... "doit", il est possible de le mettre à NULL pour ne rien récupérer.

 

Remarque: L'utilisation de la fonction WaitForSingleObject est possible pour réduire les accès:

Le handle du sémaphore sera en effet à "non signalé" si le nombre maximum est atteind.

dwWaitResult = WaitForSingleObject( hSemaphore,// handle du sémaphore

0L); // Pas de time-out

Pour clôturer le sémaphore, il faut utiliser CloseHandle(hdle);