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

Sémaphores

Déclarations dans : be/kernel/OS.h

Librairie : libroot.so

Un sémaphore est un marqueur utilisé pour synchronizer plusieurs threads. Le concept du sémaphore est simple : pour entrer dans une "section critique" protogée par un sémaphore, un thread doit d'abord "aquérir" le sémaphore, par la fonction acquire_sem(). Lorsqu'il sort de la section critique, le thread "relâche" le sémaphore avec release_sem().

L'avantage du système de sémaphore est que si un thread ne peut pas acquérir un sémaphore (parce le sémaphore doit d'abord être relâché par le précédant acquéreur), le thread bloque dans l'appel à acquire_sem(). Pendant qu'il est bloqué, le thread ne gâche aucun cycle CPU.

Pour plus d'informations sur les sémaphores, consultez "Concepts de Sémaphore". Pour des exemples de code, consultez "Exemples d'usage de sémaphore".


Fonctions


acquire_sem() , acquire_sem_etc()

                                                         
  

status_t acquire_sem(sem_id sem)

status_t acquire_sem_etc(sem_id sem,
      uint32 count,
      uint32 flags,
      bigtime_t timeout)

Ces fonctions tentent d'acquérir le sémaphore identifié par l'argument sem. Sauf en cas d'erreur, acquire_sem() ne retourne pas tant que le sémaphore n'a pas été réellement acquis.

acquire_sem_etc() est la version véritable d'acquisition : c'est essentiellement la même que acquire_sem(), mais, en plus, elle vous laisse acquérir un sémaphore plus d'une fois, et fournir un mode timeout :

 
Le kit du Noyau définit deux autres constantes de drapeau pour l'acquisition d'un sémaphore (B_CAN_INTERRUPT et B_CHECK_PERMISSION). Ces drapeaux additionnels sont utilisés par les pilotes de périphériques—ajouter ces drapeaux à l'acquisition "normale" (ou au niveau "applicatif" (user-level)) n'a pas d'effet. Malgré tout, vous devez savoir que le drapeau B_CHECK_PERMISSION est toujours ajouté lors d'une acquisition applicative afin de protéger les sémaphores globaux nécessaires au système.


A part le timeout et le nombre d'acquisition, il n'y a pas de différence entre les deux fonction d'acquisition. Spécifiquement, tout sémaphore peut être acquis par l'une ou l'autre fonction. Vous relâchez toujours un sémaphore par release_sem() (ou release_sem_etc()), peu importe quelle fonction fut utilisée pour l'acquérir.

Pour déterminer si un sémaphore est disponible, la fonction regarde le compteur du sémaphore (avant de le décrémenter) :

CODES DE RETOUR

Les autres valeurs de retour ne s'appliquent qu'à acquire_sem_etc() :


create_sem()

                                                         
  

sem_id create_sem(uint32 thread_count, const char *name)

Créé un nouveau sémaphore et retourne un sem_id unique au système qui l'identifie. Les arguments sont :

Les sem_id valides sont des entiers positifs. Vous devez toujours vérifier la validité d'un nouveau sémaphore via une séquence telle que :

   if ((my_sem = create_sem(1,"My Semaphore")) < B_OK)
      /* Si c'est moins que B_NO_ERROR, my_sem est invalide. */

create_sem() positionne le propriétaire du nouveau sémaphore à la team du thread appelant. La propriété peut être ré-affectée par la fonction set_sem_owner(). Lorsque le propriétaire meurt (lorsque tous les threads dans la team sont morts), le sémaphore est automatiquement détruit. Le propriétaire est aussi important dans un appel à delete_sem() : seuls les threads appartenant au propriétaire du sémaphore sont autorisés à détruire ce sémaphore.

CODES DE RETOUR


delete_sem()

                                                         
  

status_t delete_sem(sem_id sem)

Détruit le sémaphore identifié par l'argument. S'il y a des threads attendant dans la file de threads du sémaphore, ils sont immédiatement débloqués.

 
Cette fonction ne peut être appellée que par un thread appartenant au propriétaire du sémaphore.


CODES DE RETOUR


get_sem_count()

                                                         
  

status_t get_sem_count(sem_id sem, int32 *thread_count)

 
Pour s'amuser uniquement; ne jamais déterminer le comportement de votre code sur cette fonction.


Retourne, par référence dans thread_count, la valeur du compteur de thread du sémaphore :

Pendant que cette fonction retourne et que vous observiez la valeur de thread_count, le compteur de thread du sémaphore peut avoir changé. Bien que l'observation du compteur de thread peut vous aider pendant le deboggage de votre programme, cette fonction ne doit pas être une partie complète de la conception de votre application.

CODES DE RETOUR


get_sem_info() , get_next_sem_info()

                                                         
  

status_t get_sem_info(sem_id sem, sem_info *info)

status_t get_next_sem_info(team_id team,
      uint32 *cookie,
      sem_info *info)

Copient les informations sur un sémaphore particulier dans la structure sem_info désignée par info. La première version de ces fonctions indique le sémaphore directement, par son sem_id.

La version get_next_sem_info(), elle, vous permet de parcourir la liste des sémaphores d'une team, par appel successifs. L'argument team identifie la team que vous voulez observer; une valeur team de 0 signifie la team du thread appelant. L'argument cookie est un marqueur, positionnez-le à 0 lors du premier appel, la fonction s'occupe du reste. Celle-ci retourne B_BAD_VALUE lorsqu'il n'y a plus de sémaphore à visiter :

   /* Obtenir le sem_info pour chaque sémaphore de cette team. */
   sem_info info;
   int32 cookie = 0;
   
   while (get_next_sem_info(0, &cookie, &info) == B_OK)
      ...

CODES DE RETOUR


release_sem() , release_sem_etc()

                                                         
  

status_t release_sem(sem_id sem)

status_t release_sem_etc(sem_id sem, int32 count, uint32 flags)

La fonction release_sem() libère le thread qui attend en premier dans la file de threads du sémaphore (si il y en a un), et incrémente le compteur de thread du sémaphore. release_sem_etc() fait de même, mais pour count threads.

Normalement, relâcher un sémaphore invoque automatiquement le scheduler du noyau. Autrement dit, lorsque votre thread appelle release_sem(), vous êtes plutot sûr qu'un autre thread va être activé à votre place, même si votre thread n'avait pas reçu tout son quota de temps CPU. Si vous voulez éviter cet automatisme, appellez release_sem_etc() avec une valeur de flags à B_DO_NOT_RESCHEDULE. Prévenir la préemption automatique est particulièrement utile si vous relâcher tout un paquet de sémaphores d'un coup : en évitant la préemption vous évitez des changements de contexte non nécessaires.

CODES DE RETOUR

See also: acquire_sem()


set_sem_owner()

                                                         
  

status_t set_sem_owner(sem_id sem, team_id team)

Transfere la propriété d'un sémaphore particulier à team. Un sémaphore ne peut être la propriété que d'une seule team à la fois; en positionnant le propriétaire d'un sémaphore, vous le retirer à son propriétaire actuel.

Il n'y a pas des restrictions sur qui peut être propriétaire d'un sémaphore, ni sur qui peut transferer cette propriété. En pratique, cependant, la seule raison pour transferer la propriété est si vous écrivez un pilote de périphérique et que vous avez besoin qu'un sémaphore appartienne au noyau (la team connue, pour cet usage, comme B_SYSTEM_TEAM).

La propriété d'un sémaphore est nécessaire pour deux raisons :

Pour découvrir le propriétaire d'un sémaphore, utilisez la fonction get_sem_info().

CODES DE RETOUR


Structures et Types


sem_id

                                                         
  

typedef int32 sem_id;

Les sem_id identifient les sémaphores. L'identifiant (id) est affecté lorsque le sémaphore est créé (create_sem()). Les valeurs sont uniques à travers tout le système.


sem_info

                                                         
  

typedef struct sem_info {
      sem_id sem;
      team_id team;
      char name[B_OS_NAME_LENGTH];
      int32 count;
      thread_id latest_holder;
      }

La structure sem_info fournit des informations sur un sémaphore. Vous obtenez cette structure par la fonction get_sem_info(). L'information dans la structure sem_info est garantie consistente en interne, mais l'ensemble de la structure doit être considérée comme non à jour dès que vous la recevez. Elle fournit une photo du sémaphore tel qu'il était juste avant le retour de la fonction.

Les champs sont :

 
Le champ lastest_holder est hautement non fiable; dans certains cas, le noyau n'enregistre même pas l'acquéreur du sémaphore. Bien que vous pouviez utiliser ce champ comme aide au deboguage, vous ne devriez pas trop le prendre au sérieux.



Constantes


Drapeaux de contrôle de sémaphore


Table des matières du kit Noyau     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