Appartements multithreads

Dans un modèle d’appartement multithread, tous les threads du processus qui ont été initialisés en tant que threads libres résident dans un seul appartement. Par conséquent, il n’est pas nécessaire de marshaler entre les threads. Les threads n’ont pas besoin de récupérer et de distribuer des messages, car COM n’utilise pas de messages de fenêtre dans ce modèle.

Les appels aux méthodes d’objets dans l’appartement multithread peuvent être exécutés sur n’importe quel thread de l’appartement. Il n’y a pas de sérialisation des appels ; de nombreux appels peuvent se produire simultanément à la même méthode ou au même objet. Les objets créés dans l’appartement multithread doivent être en mesure de gérer les appels sur leurs méthodes à partir d’autres threads à tout moment.

Étant donné que les appels aux objets ne sont pas sérialisés en aucune façon, l’accès concurrentiel aux objets multithread offre les performances les plus élevées et tire le meilleur parti du matériel multiprocesseur pour les appels inter-threads, interprocessus et inter-ordinateurs. Cela signifie, toutefois, que le code des objets doit fournir la synchronisation dans leurs implémentations d’interface, généralement via l’utilisation de primitives de synchronisation telles que des objets d’événement, des sections critiques, des mutexes ou des sémaphores, qui sont décrits plus loin dans cette section. En outre, étant donné que l’objet ne contrôle pas la durée de vie des threads qui y accèdent, aucun état spécifique au thread ne peut être stocké dans l’objet (dans le stockage local des threads).

Voici quelques considérations importantes concernant la synchronisation des appartements multithread :

  • COM fournit la synchronisation des appels uniquement pour les appartements à thread unique.
  • Les appartements multithread ne reçoivent pas d’appels lors des appels (sur le même thread).
  • Les appartements multithread ne peuvent pas effectuer d’appels synchronisés d’entrée.
  • Les appels asynchrones sont convertis en appels synchrones dans des appartements multithreads.
  • Le filtre de message n’est appelé pour aucun thread dans un appartement multithread.

Pour initialiser un thread en tant que thread libre, appelez CoInitializeEx, en spécifiant COINIT_MULTITHREADED. Pour plus d’informations sur le threading de serveur in-process, consultez Problèmes de thread de serveur in-process.

Plusieurs clients peuvent appeler simultanément, à partir de différents threads, un objet qui prend en charge le thread libre. Dans les serveurs hors processus à threads libres, COM, via le sous-système RPC, crée un pool de threads dans le processus serveur et un appel client (ou plusieurs appels clients) peut être fourni par l’un de ces threads à tout moment. Un serveur hors processus doit également implémenter la synchronisation dans sa fabrique de classes. Les objets in-process avec threads libres peuvent recevoir des appels directs de plusieurs threads du client.

Le client peut effectuer un travail COM dans plusieurs threads. Tous les threads appartiennent au même appartement multithread. Les pointeurs d’interface étant passés directement d’un thread à un thread au sein d’un appartement multithread, les pointeurs d’interface ne sont pas marshalés entre ses threads. Les filtres de messages (implémentations d’IMessageFilter) ne sont pas utilisés dans les appartements multithreads. Le thread client est suspendu lorsqu’il effectue un appel COM à des objets hors de l’appartement et reprendra lorsque l’appel revient. Les appels entre processus sont toujours gérés par RPC.

Les threads initialisés avec le modèle à thread libre doivent implémenter leur propre synchronisation. Comme mentionné précédemment dans cette section, Windows active cette implémentation via les primitives de synchronisation suivantes :

  • Les objets d’événement permettent de signaler à un ou plusieurs threads qu’un événement s’est produit. N’importe quel thread au sein d’un processus peut créer un objet d’événement. Un handle à l’événement est retourné par la fonction de création d’événements, CreateEvent. Une fois qu’un objet d’événement a été créé, les threads avec un handle de l’objet peuvent attendre avant de poursuivre l’exécution.
  • Les sections critiques sont utilisées pour une section de code qui nécessite un accès exclusif à un ensemble de données partagées avant de pouvoir être exécutée et qui est utilisée uniquement par les threads au sein d’un seul processus. Une section critique est comme un tourniquet par lequel un seul thread à la fois peut passer, fonctionnant comme suit :
    • Pour s’assurer qu’aucun thread à la fois n’accède aux données partagées, le thread principal d’un processus alloue une structure de données CRITICAL_SECTION globale et initialise ses membres. Un thread entrant dans une section critique appelle la fonction EnterCriticalSection et modifie les membres de la structure de données.
    • Un thread qui tente d’entrer une section critique appelle EnterCriticalSection qui vérifie si la structure de données CRITICAL_SECTION a été modifiée. Si c’est le cas, un autre thread se trouve actuellement dans la section critique et le thread suivant est mis en veille. Un thread sortant d’une section critique appelle LeaveCriticalSection, qui réinitialise la structure de données. Lorsqu’un thread quitte une section critique, le système réveille l’un des threads en veille, qui entre ensuite dans la section critique.
  • Mutexes effectue la même fonction qu’une section critique, sauf que le mutex est accessible aux threads s’exécutant dans différents processus. Posséder un objet mutex, c’est comme avoir la parole dans un débat. Un processus crée un objet mutex en appelant la fonction CreateMutex , qui retourne un handle. Le premier thread demandant un objet mutex obtient la propriété de celui-ci. Une fois le thread terminé avec le mutex, la propriété passe à d’autres threads sur la base du premier arrivé, premier servi.
  • Les sémaphores sont utilisés pour maintenir un nombre de références sur certaines ressources disponibles. Un thread crée un sémaphore pour une ressource en appelant la fonction CreateSemaphore et en passant un pointeur vers la ressource, un nombre initial de ressources et le nombre maximal de ressources. Cette fonction retourne un handle. Un thread demandant une ressource transmet son handle de sémaphore dans un appel à la fonction WaitForSingleObject . L’objet sémaphore interroge la ressource pour déterminer si elle est disponible. Si c’est le cas, le sémaphore décrémente le nombre de ressources et réveille le thread en attente. Si le nombre est égal à zéro, le thread reste endormi jusqu’à ce qu’un autre thread libère une ressource, ce qui entraîne l’incrémentation du nombre par le sémaphore.

Accès aux interfaces entre les appartements

Choix du modèle threading

Problèmes de thread de serveur in-process

Processus, threads et appartements

Communication monothread et multithread

Appartements à thread unique