Choix d'un modèle de thread
Remonter à Utilisation de l'expert Objet Automation
Lors de la création d'un objet à l'aide de l'expert, sélectionnez le modèle de thread que votre objet peut gérer. En ajoutant la gestion des threads à votre objet COM, vous pouvez augmenter ses performances, car plusieurs clients peuvent accéder simultanément à votre application.
Le tableau suivant énumère les différents modèles de thread que vous pouvez spécifier.
Modèles de thread pour les objets COM :
Modèle de thread | Description | Avantages et inconvénients |
---|---|---|
Unique |
Le serveur ne gère pas les threads. COM sérialise les demandes des clients afin que l'application ne reçoive qu'une seule demande à la fois. |
Les clients sont traités un par un, il n'est donc pas nécessaire de gérer les threads. Pas de gains en performances. |
Apartment (ou apartment à thread unique) |
COM s'assure qu'un seul thread client peut appeler l'objet à la fois. Tous les appels des clients utilisent le thread dans lequel l'objet a été créé. |
Les objets peuvent accéder en toute sécurité à leurs propres données d'instance mais les données globales doivent être protégées en utilisant des sections critiques ou une autre forme de sérialisation. Les variables locales du thread sont utilisables sur plusieurs appels. Certains gains en performances. |
Libre (également appelé apartment à threads multiples) |
Les objets peuvent recevoir des appels d'un nombre quelconque de threads à tout moment. |
Les objets doivent protéger toutes les instances et les données globales en utilisant des sections critiques ou une autre forme de sérialisation. Les variables locales de thread ne sont pas utilisables sur plusieurs appels. |
Les deux |
Identique au modèle Libre mais les appels sortants (par exemple, les callbacks) sont assurés de s'exécuter dans le même thread. |
Maximum de performances et de souplesse. N'impose pas à l'application de gérer les threads pour les paramètres spécifiés pour les appels sortants. |
Neutre |
Plusieurs clients peuvent appeler l'objet sur différents threads en même temps, mais COM assure qu'il n'y a pas de conflit entre deux appels. |
Vous devez vous protéger des conflits de thread impliquant des données globales ou les données d'instance sont accédées par plusieurs méthodes. Ce modèle ne doit pas être utilisé avec les objets ayant une interface utilisateur (contrôles visuels). Ce modèle est disponible uniquement sous COM+. Sous COM, il est équivalent au modèle Appartement. |
Remarque : Les variables locales sont toujours fiables (sauf celles des callbacks) indépendamment du modèle de thread. En effet, les variables locales sont stockées dans la pile et chaque thread dispose de sa propre pile. Les variables locales des callbacks peuvent n'être pas fiables si vous utilisez le modèle libre.
Le modèle de thread que vous choisissez dans l'expert détermine comment l'objet est publié dans le registre. Vous devez être certain que l'implémentation de l'objet est conforme au modèle de thread choisi. Pour des informations générales sur l'écriture de code adapté aux threads, voir Ecriture d'applications multithreads.
Pour les serveurs en processus, l'initialisation du modèle de thread dans l'expert définit la clé du modèle de thread dans l'entrée de registre CLSID.
Les serveurs hors processus sont recensés comme EXE, et Delphi initialise COM pour le modèle de thread le plus élevé nécessaire. Par exemple, si un EXE contient un objet à thread libre, il est initialisé pour les threads libres, ce qui signifie qu'il peut fournir la gestion attendue pour tous les objets à thread libre ou apartment contenus dans l'EXE. Pour redéfinir manuellement le comportement des threads dans les EXE, utilisez la variable ComObj.CoInitFlags.
Sommaire
Ecriture d'un objet gérant le modèle de thread libre
Utilisez le modèle de thread libre (ou both) au lieu du modèle apartment chaque fois que l'objet doit être accédé par plusieurs threads. Considérons, par exemple, une application client connectée à un objet sur une machine distante. Lorsque le client distant appelle une méthode sur cet objet, le serveur reçoit l'appel sur un thread appartenant au groupe de threads de la machine serveur. Le thread recevant effectue l'appel localement sur l'objet réel et, l'objet supportant le modèle de thread libre, le thread peut effectuer un appel direct dans l'objet.
Si, au contraire, l'objet avait supporté le modèle de thread apartment, l'appel aurait dû être transféré au thread dans lequel l'objet a été créé et le résultat aurait dû être transféré en retour dans le thread recevant avant de revenir au client. Cette approche nécessite des mécanismes de marshaling supplémentaires.
Pour supporter le modèle de thread libre, vous devez considérer la façon dont chaque méthode accédera aux données d'instance. Si la méthode est écrite pour des données d'instance, vous devez utiliser les sections critiques, ou tout autre forme de sérialisation, pour protéger les données d'instance. En outre, la sérialisation des appels critiques est moins lourde que l'exécution du code de marshaling de COM.
Remarquez que si les données d'instance sont accessibles en lecture seulement, la sérialisation n'est pas nécessaire.
Les serveurs en processus à thread libre peuvent améliorer leurs performances en se comportant comme objet extérieur d'un agrégat avec le marshaler à thread libre. Le marshaler à thread libre propose un raccourci pour la gestion standard COM du thread quand une DLL à thread libre est appelée par un hôte (un client) qui n'utilise pas de thread libre.
Pour effectuer l'agrégation avec le marshaler à thread libre, vous devez :
- Appeler CoCreateFreeThreadedMarshaler, en lui transmettant l'interface IUnknown de votre objet qui doit utiliser le marshaler à thread libre résultant : CoCreateFreeThreadedMarshaler(self as IUnknown, FMarshaler); CoCreateFreeThreadedMarshaler(static_cast<IUnknown *>(this), &FMarshaler);. Cette ligne affecte l'interface du marshaler à thread libre à un membre de classe, FMarshaler.
- En utilisant l'éditeur de bibliothèques de types, ajoutez l'interface IMarshal à l'ensemble des interfaces que votre CoClasse implémente.
- Dans la méthode QueryInterface de votre objet, déléguez tous les appels de IDD_IMarshal au marshaler à thread libre (stocké dans FMarshaler ci-dessus).
Avertissement : Le marshaler à thread libre viole les règles normales du marshaling COM pour permettre une meilleure efficacité. Il doit être utilisé avec prudence. En particulier, il ne doit être agrégé qu'avec des objets à thread libre dans un serveur en processus et ne doit être instancié que par l'objet qui l'utilise (et pas par un autre thread).
Ecriture d'un objet supportant le modèle de thread apartment
Pour implémenter le modèle de thread apartment (à thread unique), il est nécessaire de suivre certaines règles :
- Le premier thread de l'application qui a été créé est le thread principal de COM. C'est habituellement le thread sur lequel WinMain a été appelé. Ce doit être également le dernier thread à désinitialiser COM.
- Chaque thread du modèle de thread apartment doit posséder une boucle de messages et la file des messages doit être vérifiée fréquemment.
- Lorsqu'un thread obtient un pointeur sur une interface COM, les méthodes de cette interface ne peuvent être appelées que depuis ce thread.
Le modèle apartment à thread unique est un moyen terme entre la solution qui consiste à ne fournir aucun support des threads et celle qui assure le support complet du multi-thread dans le modèle libre. Un serveur conforme au modèle apartment est la garantie que le serveur sérialise les accès à toutes ses données globales (par exemple, son nombre d'objets). En effet, différents objets peuvent tenter d'accéder aux données globales depuis différents threads. Cependant, les données des instances de l'objet sont sécurisées, car les méthodes sont toujours appelées sur le même thread.
Habituellement, les contrôles destinés aux navigateurs Web utilisent le modèle de thread apartment, car les applications navigateur initialisent toujours leurs threads en tant qu'apartment.
Ecriture d'un objet supportant le modèle de thread neutre
Avec COM+, vous pouvez utiliser un autre modèle de thread, à mi-chemin entre thread libre et thread apartment : le modèle neutre. Comme le modèle de thread libre, ce modèle permet à plusieurs threads d'accéder simultanément à votre objet. Il n'y a pas de marshaling supplémentaire pour transférer au thread dans lequel l'objet a été créé. Cependant votre objet est assuré de ne pas recevoir d'appels contradictoires.
L'écriture d'un objet utilisant le modèle de thread neutre respecte sensiblement les même règles que l'écriture d'un objet gérant le modèle de thread apartment, sauf qu'il n'est pas nécessaire de protéger les données de l'instance des conflits de threads, elles peuvent être accédées par différentes méthodes de l'interface de l'objet. Toutes les données d'instance qui ne peuvent être accédées que par une seule méthode d'interface sont automatiquement adaptées aux threads.