Table des matières du Be Book     Index du kit du Noyau

Concepts d'un sémaphore

Un sémaphore agit comme une clef qu'un thread doit obtenir afin de continuer son exécution. Tout thread pouvant identifier un sémaphore particulier peut tenter de l'acquérir en passant son identifiant sem_id—un nombre global au système affecté lors de la création du sémaphore—à la fonction acquire_sem(). La fonction bloque tant que le sémaphore n'est pas acquis.

 
Une fonction alternative, acquire_sem_etc() vous permet de spécifier la quantité de temps que vous voulez bien attendre l'acquisition du sémaphore, et vous permet d'acquérir le sémaphore plus d'une fois d'un seul coup. Sauf indication contraire, les caractéristiques de acquire_sem() s'appliquent aussi à acquire_sem_etc().)


Lorsqu'un thread acquère un sémaphore, ce sémaphore devient (typiquement) indisponible pour des acquisitions par d'autres threads. Le sémaphore reste indisponible jusqu'à ce qu'elle soit l'objet d'un appel à la fonction release_sem().

Le code qu'un sémaphore "protège" est entouré par les appels à acquire_sem() et release_sem(). La disposition de ces fonctions dans votre code suit habituellement ce motif :

   if (acquire_sem(my_semaphore) == B_NO_ERROR) {
      /* Ici, le code protégé. */
      release_sem(my_semaphore);
   }

Gardez à l'esprit que...


La file d'attente de threads

Chaque sémaphore a sa propre file de thread : c'est une liste identifiant les threads qui attendent l'acquisition du sémaphore. Un thread qui tente d'acquérir un sémaphore indisponible est placé à la fin de la file de thread du sémaphore, où il attend bloqué dans l'appel à acquire_sem(). Chaque appel à release_sem() débloque le thread en tête de file du sémaphore, en l'autorisant ainsi à revenir de son appel à acquire_sem().

Les sémaphores ne font pas de discrimination entre les threads acquéreurs—ils ne priorisent pas ni ne réordonnent les threads dans leurs files d'attente—le plus vieux thread en attente d'acquisition est toujours le prochain acquéreur du sémaphore.


Le compteur de thread

Pour connaître sa disponibilité, un sémaphore regarde son compteur de thread. C'est une variable compteur initialisée lors de la création du sémaphore. Pratiquement, la valeur itiniale d'un compteur de thread (qui est passée comme premier argument de create_sem()) est le nombre de threads qui pourront acquérir le sémaphore en même temps. (Comme nous le verrons plus tard, ce n'est pas toute l'histoire, mais c'est suffisant pour l'instant). Par exemple, un sémaphore utilisé comme verrou mutuellement exclusif voit son compteur de thread initialisé à 1—autrement dit, un seul thread peut acquérir le sémaphore à un moment donné.

 
Un compteur de thread initialisé à 1 est de loin le plus courant; un compteur de thread de 0 est également utile. Les autres valeurs sont beaucoup moins courantes.


Les appels à acquire_sem() et release_sem() modifient le compteur de thread du sémaphore : acquire_sem() décrémente le compteur, et release_sem() l'incrémente. Lorsque vous appellez acquire_sem(), la fonction regarde le compteur de thread (avant de le décrémenter) pour déterminer si le sémaphore est disponible :

La valeur initiale du compteur de thread n'est pas une limite inviolable du nombre de threads qui pourront acquérir un sémaphore donné—c'est juste la valeur initiale du compteur de thread du sémaphore. Par exemple, si vous créez un sémaphore avec un compteur de thread initial de 1 et que vous appellez immédiatement release_sem() cinq fois, le compteur de thread du sémaphore augmentera à 6. De plus, bien que vous ne pouviez pas initialiser le compteur de thread à une valeur négative, une valeur initiale de zéro est fréquente—c'est un des usages des sémaphores pour imposer un ordre d'exécution (comme montré plus bas).

En résumé, il y a trois ensembles typiques de valeur de compteur de thread :

Malgré qu'il soit possible d'obtenir la valeur du compteur de thread d'un sémaphore (en regardant un champ dans la structure sem_info d'un sémaphore, comme décrit plus loin), vous ne devriez faire cela qu'uniquement par amusement—lors du déboggage, par exemple.

 
Vous ne devez jamais déterminer le comportement de votre code en vous basant sur la valeur du compteur de thread d'un sémaphore.



Détruire un sémaphore

Chaque sémaphore est la propriété d'une team (la team du thread qui a appellé create_sem()). Lorsque le dernier thread d'une team meurt, il emporte avec lui les sémaphores de cette team.

Avant la mort d'une team, vous pouvez détruire explicitement un sémaphore via la fonction delete_sem(). Notez cependant que delete_sem() doit être appellée par un thread membre de la team propriétaire du sémaphore—vous ne pouvez pas détruire les sémaphores d'une autre team.

Vous pouvez détruire un sémaphore même s'il y a encore des threads dans sa file d'attente. Toutefois, vous voudrez habituellement éviter cela, donc détruire un sémaphore mérite quelques réflexions : lorsque vous détruisez un sémaphore, (ou lorsqu'il meurt naturellement), tous les threads en attente sont immédiatement autorisés à reprendre leur exécution—ils retournent tous de acquire_sem() en même temps. Vous pouvez différencier une acquisition "normale" d'une acquisition "sémaphore détruit" via la valeur retournée par acquire_sem() (les valeurs de retour spécifiques sont listées dans la description de la fonction, plus bas).


Sémaphores inter-applications

Le sem_id qui identifie un sémaphore est une clée unique à tout le système—les sem_id que vous créez dans votre application vont identifier vos sémaphores dans tous les autres applications également. Il est possible, alors, de diffuser les sem_id des sémaphores que vous avez créés et d'ainsi permettre à d'autres applications de les acquérir et de les relâcher—mais ce n'est pas une très bonne idée.

 
Un sémaphore est mieux contrôlé s'il est créé, acquis, relâché et détruit au sein de la même team.


Si vous voulez fournir un accès protégé à un service ou une ressource aux autres applications, vous devez accepter des messages des autres applications et engendrer alors des threads qui acquériront et relâcheront les sémaphores appropriés.


Table des matières du Be Book     Index du kit du Noyau


Le Be Book,
...en superbe HTML...
pour BeOS Release 5.

Copyright © 2000 Be, Inc. Tous droits réservés.
Traduit en Français par Philippe Houdoin