Table des matières du kit d'application     Index du kit d'application

BLooper

Dérivée de: public BHandler

Déclarée dans: be/app/Looper.h

Librairie: libbe.so

Résumé

Un objet BLooper crée un "message en boucle" qui reçoit les messages envoyés ou postés par BLooper. La boucle de message s'exécute dans un thread séparé qui est créé quand le BLooper reçoit un appel à la fonction Run(). Si vous avez créé votre propre BLooper, vous pouvez invoquer la fonction Run() depuis votre constructeur.

Vous dîtes à la boucle de s'arrêter en envoyant à BLooper un message B_QUIT_REQUESTED, qui invoquera la fonction Quit() de l'objet. Vous pouvez aussi appeler directement Quit(), mais vous devez d'abord verrouiller (Lock()) l'objet (le verrouillage de BLooper est expliqué plus loin). Quit() supprimera l'objet BLooper pour vous.

 
La classe BApplication, la sous-classe la plus importante de BLooper, fait une entorse à la description donnée ci-dessus:



Messages et Handlers

Vous pouvez délivrer des messages au thread BLooper en...

Lorsque les messages arrivent, ils sont ajoutés à l'objet BMessageQueue de BLooper. L'objet BLooper prend les messages de la queue dans l'ordre où ils sont arrivés, et appelle DispatchMessage() pour chacun d'eux. DispatchMessage() verrouille l'objet BLooper et envoie le message à un objet BHandler  en invoquant la fonction MessageReceived(). Mais quel BHandler va recevoir le message envoyé par BLooper? 

Après que l'handler soit terminé (quand MessageReceived() retourne une valeur), le BMessage est automatiquement détruit et le BLooper est déverrouillé.


Verrouillage

L'accès beaucoup de fonctions de BLooper (et certaines fonctions de BHandler) est protégé par des verrous. Pour appeler des fonctions verrouillées (ou des groupes de fonctions), vous devez d'abord appeler Lock(), et ensuite appeler Unlock() quand vous avez fini. Le verrou est limité au thread appelant: les appels à Lock()/Unlock() peuvent être emboîter à l'intérieur du thread. Gardez en mémoire que chaque appel à Lock() must être compensé par un appel à Unlock().

Le constructeur BLooper verrouille automatiquement l'objet. Il est déverrouillé quand Run() est invoqué. Cla signifie que la fonction Run()—ainsi que n'importe quelle fonctions protégée que vous appelez avant l'appel à Run()—doit être appelée depuis le thread qui construit le BLooper.


Allocation

Parce qu'ils se suppriment (delete) eux même lorsqu'ils quittent, BLoopers ne peuvent être alloués sur la pile; vous avez à les construire avec new.


Hook Functions


Constructeur et Destructeur


BLooper()

                                                         
  

BLooper(const char *nom = NULL,
      int32 priority = B_NORMAL_PRIORITY,
      int32 portCapacity = B_LOOPER_PORT_DEFAULT_CAPACITY)

BLooper(BMessage *archive)

Assigne un nom à l'objet BLooper et le verrouille (en appelant Lock()). priority est une valeur indiquant la quantité de disponibilité de temps CPU que la boucle de message recevra lorsqu'elle commencera à s'exécuter, et portCapacity correspond au nombre de messages que BLooper peut contenir dans son "port de messages" (ce n'est pas la queue de messages, comme expliqué plus loin).

Après avoir construit le BLooper, vous devez lui demander de s'exécuter (Run()). Parce que l'objet est verrouillé, Run() peut seulement être appelé depuis le thread qui a construit l'objet. Il est autorisé d'invoquer Run() depuis une sous-classe du constructeur.

Priorité

Une série de valeurs de priorité est définie dans kernel/OS.h; de la plus petite à la plus grande:

B_LOW_PRIORITY Pour les threads s'exécutant en tache de fond et qui ne devraient pas interrompre d'autres threads.
B_NORMAL_PRIORITY Pour tous les threads ordinaires, incluant le thread principal.
B_DISPLAY_PRIORITY Pour les threads associés aux objets de l'interface utilisateur, incluant les threads des fenêtres.
B_URGENT_DISPLAY_PRIORITY Pour les threads de l'interface qui demandent plus d'attention que les fenêtres ordinaires.
B_REAL_TIME_DISPLAY_PRIORITY Pour les threads qui font des animations sur l'écran.
B_URGENT_PRIORITY Pour les threads effectuant des traitements avec de fortes contraintes de temps.
B_REAL_TIME_PRIORITY Pour les threads contrôlant des processus temps réel qui ont besoin d'un accès immédiat au CPU.

Capacité du Port

Les messages qui sont envoyés à un BLooper arrivent tout d'abord dans un port (comme défini dans le Kernel Kit), et sont ensuite déplacé vers le BMessageQueue. La capacité du BMessageQueue est virtuellement illimitée; la capacité du port ne l'est pas. Bien que les messages sont déplacés du port à la queue aussi rapidement que possible, le port peut se boucher. Un port plein va bloquer les futurs messages envoyés.

La capacité par défaut du port (100), devrait être suffisante pour la plupart des applications, mais vous pouvez l'augmenter par l'argument portCapacity.


~BLooper()

                                                         
  

virtual ~BLooper()

Libère la queue de messages et tous les messages en instance ainsi que la boucle de messages. Les BHandlers qui ont été ajoutés au BLooper ne sont pas détruits, mais les objets BMessageFilter ajoutés comme filtres communs sont eux détruits.

En général, vous ne devriez jamais détruire (delete) vos objets BLooper: à part l'exception des objets BApplication, BLoopers sont détruits par la fonction Quit().

 
Si vous créez une classe dérivée de BLooper qui possède plusieurs héritages, soyez sûr que la classe dont toutes les autres héritent dérive bien de BLooper; Autrement, vous allez planter quand vous essaierez de fermer la fenêtre. Cela se produit à cause d'une interaction avec le thread de la fenêtre et la façon dont C++ supprime les objets d'une classe possédant de multiples héritages. En d'autres mots:


      class maClasse : public BLooper, public AutreClasse {
      ...
      };

est enregistrée, pendant que

      class maClasse : public AutreClasse, public BLooper {
      ...
      };

ne l'est pas.


Fonctions Statiques


LooperForThread()

                                                         
  

static BLooper *LooperForThread(thread_id thread)

Retourne l'objet BLooper qui a créer le thread spécifié, ou NULL si le thread ne provient pas d'un BLooper.


Fonctions Membres


AddCommonFilterList() , RemoveCommonFilterList() , SetCommonFilterList() , CommonFilterList()

                                                         
  

virtual void AddCommonFilter(BMessageFilter *filtre)

virtual bool RemoveCommonFilter(BMessageFilter *filtre)

virtual void SetCommonFilterList(BList *filtres)

BList *CommonFilterList(void) const

 
Pour toutes ces fonctions sauf CommonFilterList(), le BLooper doit être verrouillé.


Ces fonctions contrôlent une liste BLooper contenant des BMessageFilters. Les filtres de messages sont des  objets qui passent au crible les messages rentrants. Dans le cas de BLooper, chaque message passe à travers tous les filtres de la liste avant d'être passé à DispatchMessage(). L'ordre des filtres dans la liste est déterminée. Se reporter à la classe BMessageFilter pour les détails concernant le fonctionnement des filtres de messages.

AddCommonFilter() ajoute le filtre à la fin de la liste de filtres (crée un conteneur BList si nécessaire).

RemoveCommonFilter() retire filtre de la liste, mais ne libère pas le filtre. Retourne true si l'opération est effectuée avec succès, et false s'il ne peut pas trouver le filtre spécifié.

SetCommonFilterList() détruit la liste courante de filtres ainsi que son contenu, et remplace celle-ci par filtres. Tous les éléments de filtres doivent être un pointeur BMessageFilter. Le BLooper prend possession de tous les objets dans filtres, ainsi que de filtres lui même. Si filtres est NULL, la liste courante est détruite sans remplacement.

CommonFilterList() retourne un pointeur sur la liste courante. Vous pouvez examiner la liste mais vous ne devriez pas la modifier ou l'effacer.


AddHandler() , RemoveHandler() , HandlerAt() , CountHandlers() , IndexOf()

                                                         
  

void AddHandler(BHandler *handler)

bool RemoveHandler(BHandler *handler)

BHandler *HandlerAt(int32 index) const

int32 CountHandlers(void) const

int32 IndexOf(BHandler *handler) const

AddHandler() ajoute handler à la liste BLooper des objets BHandler, et RemoveHandler() l'enlève. Seuls les BHandlers qui ont été ajoutés à la liste sont susceptibles de répondre aux messages qu'envoie BLooper.

AddHandler() échoue si handler appartient déjà à un BLooper; un BHandler ne peut pas appartenir à plus d'un BLooper à la fois. Il peut changer son affiliation de temps en temps, mais il doit être enlevé d'un BLooper avant de n'être ajouté à un autre. RemoveHandler() retourne true en cas de succès lors de l'enlèvement du BHandler au BLooper, et false dans le cas contraire ou si handler n'appartient pas au BLooper.

AddHandler() appelle aussi la fonction SetNextHandler() sur handler  pour assigner le BLooper comme étant son prochain handler par défaut. RemoveHandler() appelle la même fonction pour définir à NULL le prochain handler de handler.

HandlerAt() retourne l'objet BHandler qui est actuellement localisé à index dans la liste de BLoopers des handlers éligibles, ou NULL si l'index est en dehors de la liste. Les indices commencent à 0 et il n'y a pas de trou dans la liste. CountHandlers() retourne le nombre d'objets actuellement dans la liste; le décompte devrez toujours être au moins égal à 1, la liste incluant automatiquement le BLooper lui même. IndexOf() retourne l'index de handler, ou B_ERROR si cet objet n'est pas dans la liste.

Pour que ces fonctions marchent, le BLooper doit être verrouillé.

Voir aussi: BHandler::Looper(), BHandler::SetNextHandler(), PostMessage() et la classe BMessenger


Archive() voir BArchivable::Archive()


CommonFilterList() voir AddCommonFilterList()


CountHandlers() voir AddHandler()


CountLockRequests() voir LockingThread()


CountLocks() voir LockingThread()


CurrentMessage() , DetachCurrentMessage()

                                                         
  

BMessage *CurrentMessage(void) const

BMessage *DetachCurrentMessage(void)

Le message qu'un BLooper passe à son ou ses handlers est appelé le "message courant". Ces fonctions accèdent au message courant; elles ne font rien (elles retournent NULL) lorsqu'elles sont appelées d'en dehors de la boucle de message.

CurrentMessage() retourne simplement un pointeur sur le message courant sans affecter l'objet BMessage. Ceci est particulièrement utile aux fonctions qui répondent à des messages du système (comme MouseDown() et ScreenChanged()), mais ça n'envoie pas l'objet complet BMessage qui a initialisé la réponse.

DetachCurrentMessage() enlève le message courant de la queue de messages et donne l'appartenance du message à l'appelant; la suppression du message est la responsabilité de l'appelant. Ceci est utile si vous voulez retarder la réponse au message sans l'attacher au BLooper. Mais soyez attentif—si l'envoyeur du message attend une réponse, détacher le message et le retenir va bloquer l'envoyeur.


DetachCurrentMessage() voir CurrentMessage()


DispatchMessage()

                                                         
  

virtual void DispatchMessage(BMessage *message, BHandler *cible)

DispatchMessage() est la fonction centrale de traitement des messages de la classe BLooper. Elle est appelée automatiquement lorsque les messages arrivent dans la queue de la boucle, une invocation par message. Vous n'invoquez jamais DispatchMessage() vous-même.

L'implémentation par défaut passe message à handler en invoquant le dernier MessageReceived():

   cible->MessageReceived(message);

La seule exception se rencontre lorsque message.what est B_QUIT_REQUESTED et handler est le looper lui même; dans ce cas, l'objet invoque sa propre fonction QuitRequested().

Vous pouvez passer outre cette fonction pour distribuer les messages que votre propre application définie ou reconnaît. Tous les messages sans handler devraient être passés à la classe de base, comme dans l'exemple ci-dessous:

   void MonLooper::DispatchMessage(BMessage *msg, BHandler *cible)
   {
      switch ( msg->what ) {
      case MON_MESSAGE1:
         ...
         break; 
      case MON_MESSAGE2:
         ...
         break; 
      default:
         baseClass::DispatchMessage(msg, cible);
         break;
       }
   }

De plus, vous ne devez pas détruire message; il est détruit à votre place.

Le système verrouille le BLooper avant d'appeler DispatchMessage() et garde celui-ci verrouillé tout le temps d'exécution de la fonction.


HandlerAt() voir AddHandler()


IndexOf() voir AddHandler()


IsLocked() voir LockingThread()


Lock() , LockWithTimeout() , Unlock()

                                                         
  

bool Lock(void)

status_t LockWithTimeout(bigtime_t timeout)

void Unlock(void)

Lock() verrouille le BLooper. Les verrous sont définit à l'intérieur du contexte d'un thread; tant qu'un BLooper est verrouillé, aucun autre thread ne peut invoquer ses fonctions les plus importantes (AddHandler(), DispatchMessage(), etc.)

Si le looper est déjà verrouillé (par un quelconque autre thread), Lock() va bloquer jusqu'à ce que le looper soit déverrouillé. Pour définir une échéance pour le blocage, utilisez plutôt LockWithTimeout(). timeout est mesuré en microsecondes; si c'est 0, la fonction retourne immédiatement (avec ou sans le verrou); si c'est B_INFINITE_TIMEOUT, elle bloque sans limite.

Unlock() déverrouille un looper verrouillé. Elle ne peut être appelée que par le thread qui possède le verrou à ce moment là.

Les appels à Lock()/LockWithTimeout() et Unlock() peuvent être imbriqués, mais un verrouillage doit ensuite être déverrouillé. Un simple Unlock() ne défera pas une série d'appel à Lock().

CODES DE RETOUR

Lock() retourne true si elle a été capable de verrouiller le looper, ou s'il est déjà verrouillé par le thread appelant, et false dans les autres cas.

LockWithTimeout() retourne:


LockingThread() , IsLocked() , CountLocks() , CountLockRequests() , Sem()

                                                         
  

thread_id LockingThread(void) const

bool IsLocked(void) const

int32 CountLocks(void) const

int32 CountLockRequests(void) const

sem_id Sem(void) const

Ces fonctions peuvent être utiles lors du déboguage d'un BLooper.

LockingThread() retourne le thread qui possède le BLooper verrouillé, ou –1 si le BLooper n'est pas verrouillé.

IsLocked() retourne true si le thread possède le BLooper verrouillé (si c'est le thread verrouilleur) et false dans le cas contraire (si un autre thread est le thread verrouilleur ou si le BLooper n'est pas verrouillé).

CountLocks() retourne le nombre de fois que le thread verrouilleur a verrouillé le BLooper—le nombre d'appels à Lock() (ou LockWithTimeout()) qui n'ont pas encore été contrebalancés par un appel à Unlock().

CountLockRequests() retourne le nombre de threads qui essaient actuellement de verrouiller le BLooper. Le compteur inclue le thread qui possède actuellement le verrou ainsi que tous les threads qui attendent pour l'acquérir.

Sem() retourne l'identifiant du sémaphore (sem_id) que le BLooper utilise pour implémenter le mécanisme de verrou.

Voir aussi: Lock()


LockWithTimeout() voir Lock()


MessageReceived()

                                                         
  

virtual void MessageReceived(BMessage *message)

Appelle simplement la fonction dérivée. Pour la version courante, l'implémentation de cette fonction de BLooper ne fait rien d'importance.

Voir aussi: BHandler::MessageReceived()


MessageQueue()

                                                         
  

BMessageQueue *MessageQueue(void) const

Retourne la queue qui contient les messages délivrés par le thread du BLooper. Vous n'avez que rarement à examiner la queue de message directement.

Voir aussi: la classe BMessageQueue.


PostMessage()

                                                         
  

status_t PostMessage(BMessage *message)

status_t PostMessage(uint32 commande)

status_t PostMessage(BMessage *message,
      BHandler *handler,
      BHandler *replyHandler = NULL)

status_t PostMessage(uint32 commande,
      BHandler *handler,
      BHandler *replyHandler = NULL)

 
PostMessage() est similaire à BMessenger::SendMessage(). La version BMessenger est préférable (c'est un peu plus sûr PostMessage()).


Place un message à la fin de la queue de messages de BLooper. Le message sera traité par DispatchMessage() quand il sera arrivé à la tête de la file d'attente.

Le message peut être un objet BMessage complet (message), ou juste une commande constante (commande). Dans le premier cas, le message est copié et l'appelant retient le propriétaire de l'argument, qui sera détruit aussitôt que PostMessage() prend fin. Dans le second cas, un objet BMessage est créé (et détruit) pour vous.

handler est l'handler désigné pour le message, et doit faire partie de la chaîne d'handlers de ce BLooper. Si handler est (littéralement) NULL, l'handler désigné est l'handler préféré de BLooper au moment où DispatchMessage() est appelé. Pour les versions de PostMessage() qui n'ont pas un handler en argument, l'handler désigné est l'objet BLooper lui-même.

Les réponses au message sont délivrées à replyHandler. Si un replyHandler n'est pas spécifié, les réponse sont envoyées à be_app_messenger.

 
Un BLooper ne devrez jamais poster un message à lui-même à l'intérieur de sa propre boucle de messages.


CODES DE RETOUR


PreferredHandler() voir SetPreferredHandler()


Quit()

                                                         
  

virtual void Quit(void)

Stoppe la boucle de messages (si elle est en cours d'exécution), et détruit le BLooper. L'objet doit être verrouillé.

Quand Quit() est appelée depuis le thread de BLooper, la boucle de messages est immédiatement arrêtée et les messages dans la queue sont détruits (sans avoir été traités). Notez que dans ce cas, Quit() ne retourne rien jusqu'à ce que le thread appelant soit fini.

Quand elle est appelée depuis un autre thread, Quit() attend que tous les messages actuellement dans la queue soient traités avant de détruire la boucle de messages. Elle retourne après que le BLooper a été détruit.


QuitRequested()

                                                         
  

virtual bool QuitRequested(void)

Fonction de Hook qui est invoquée lorsque le BLooper reçoit un message B_QUIT_REQUESTED. Vous n'invoquez jamais cette fonction directement. Les classes dérivées implémentent cette fonction pour retourner true si c'est bon pour quitter ce BLooper, et false si ce n'est pas bon. Notez que cette fonction ne quitte pas l'objet—le code qui envoie le message B_QUIT_REQUESTED le fait.

L'implémentation par défaut de QuitRequested() de BLooper retourne toujours true.


RemoveCommonFilter() voir AddCommonFilterList()


Run()

                                                         
  

virtual thread_id Run(void)

Crée le thread contenant la boucle de messages et l'exécute. Run() exige que le BLooper soit verrouillé (une seule fois!) quand il est appelé; il déverrouille l'objet avant de terminer. Rappelez-vous qu'un BLooper est verrouillé lorsqu'il est construit.

 
Appeler Run() sur un BLooper en cours d'exécution vous placera dans le débogueur.


CODES DE RETOUR


AddCommonFilter()


SetPreferredHandler() , PreferredHandler()

                                                         
  

void SetPreferredHandler(BHandlerAddCommonFilter() *handler) const

BHandler *PreferredHandler(void)

Ces fonctions définissent et retournent l'handler préféré de BLooper—l'objet BHandler qui gère les messages qui n'ont pas été spécifiquement associé à un autre BHandler.

Pour désigner l'handler préféré—quelque soit l'objet qu'il peut être—comme cible d'un message, passez NULL pour l'handler cible à PostMessage() ou au constructeur BMessenger.

Poster ou envoyer des messages à l'handler préféré peut être utile. Par exemple, dans le kit d'interface, les objets BWindow définissent la vue centrale courante comme l'handler préféré. Ceci permet aux autres objets—comme BMenuItems et BButtons—de cibler les messages vers la BView qui a actuellement le focus, sans savoir laquelle c'est. Par exemple, en postant ses messages au handler préféré de la fenêtre, un menu Couper peut être sûr qu'il agira sur n'importe quelle vue qui contient la sélection courante. Voir le chapitre sur le kit d'interface pour des informations sur les fenêtres, les vues, et le rôle de la vue centrale.

Par défaut, BLoopers n'a pas d'handler préféré; jusqu'à ce qu'il y en ait un de défini, PreferredHandler() retourne NULL. Notez que de toute manière, les messages ciblant l'handler préféré sont distribués au BLooper tant que l'handler préféré est NULL. En d'autres termes, le BLooper fait office d'handler préféré, tant que celui par défaut est à NULL.

Voir aussi: BControl::SetTarget() et BMenuItem::SetTarget() dans le Kit d'Interface, PostMessage()


Thread() , Team()

                                                         
  

thread_id Thread(void) const

team_id Team(void) const

Ces fonctions identifient le thread qui exécute la boucle de messages et le team à qui elle appartient. Thread() retourne B_ERROR si Run() n'a pas encore été appelé pour créer le thread et commencer la boucle. Team() retourne toujours l'identifiant du team de l'application (team_id).


Unlock() voir Lock()


Constants


B_LOOPER_PORT_DEFAULT_CAPACITY

                                                         
  

#define B_LOOPER_PORT_DEFAULT_CAPACITY 100

La capacité par défaut du port qui contient les messages entrants avant que ceux ci ne soient placer dans la BMessageQueue du BLooper. La capacité est définie dans le constructeur de BLooper.


Table des matières du kit d'application     Index du kit d'application


The Be Book,
...in lovely HTML...
for BeOS Release 5.

Copyright © 2000 Be, Inc. All rights reserved..