Com Marshalling sera-t-il (toujours) nécessaire pour un objet avec ThreadingModel tous les deux?

StackOverflow https://stackoverflow.com/questions/19847555

Question

Ceci est déclenché par une autre question.

Plus précisément, j'ai une classe COM en processus, qui est définie dans le Registre CLSID comme ayant un ThreadingModel de Both.

Notre processus active cet objet à travers CoCreateInstance (ne pas CoCreateInstanceEx, si cela compte même pour un serveur DLL en PROC)

Étant donné un modèle de filetage de Bothet compte tenu des règles énumérées dans le docs:

Threading model of server | Apartment server is run in
------------------------------------------------------
Both                      | Same apartment as client

Et compte tenu de ce que Hans écrit dans l'autre réponse:

... Le maréchalage se produit lorsque l'appel client doit être effectué sur un autre fil. ... peut se produire lorsque le filetage de threading spécifié dans l'élément Comclass l'exige. En d'autres termes, lorsque l'objet COM a été créé sur un thread mais est appelé sur un autre et que le serveur n'est pas une file d'attente.

Ma conclusion provisoire serait qu'un tel objet jamais Besoin de marasme implicite des appels à ses interfaces, car l'objet vivra toujours dans le même appartement que son client.

Est-ce correct, même si le processus client s'exécute comme Sta?

Était-ce utile?

La solution

Oui, il peut y avoir un maréchalage.

Si le client de votre classe COM fonctionne dans un STA et que vous essayez d'invoquer votre classe à partir d'un autre appartement, il devra rassembler l'appartement dans lequel il a été créé.

La terminologie com peut être vraiment déroutante. Lorsque vous vous référez à un «client» dans ce cas, vous faites vraiment référence à un thread, pas à l'application entière (comme cela le serait).

Both signifie simplement que le modèle de threading du serveur est conforme au client qui l'instancie. Autrement dit, lorsque vous instanciez votre classe, il prend le modèle de filetage du fil sur lequel il a été créé. Étant donné que vous instanciez le serveur dans un STA, votre serveur utilisera STA, ce qui signifie qu'il ne peut être invoqué que sur le thread qui l'a créé; Si un autre fil essaie de l'invoquer, il se matera au fil sur lequel il a été créé.

Autres conseils

Je ne peux pas m'en empêcher de publier cela, bien que ce ne soit pas une réponse directe à la question.

Il y a un brillant article MSKB de The Golden Ages of Com: Info: descriptions et fonctionnement des modèles de filetage ole. Toujours là, et a toutes les informations pertinentes. Le fait est que vous ne devez pas vous soucier de savoir s'il y a un maréchalage ou non, si vous suivez les règles. Enregistrez simplement votre objet en tant que ThreadingModel=Both, agréger le commissaire franc-seh CoCreateFreeThreadedMarshaler, et être fait. Com fera le maréchalage si nécessaire, de la meilleure façon possible. Selon le modèle d'appartement du client, le code client peut recevoir le pointeur direct vers votre interface, s'il suit également les règles.

Toute interface "Alien" que vous pouvez recevoir lorsqu'une méthode de votre interface est appelée sera valide dans la portée de l'appel, car vous restez sur le même fil. Si vous n'avez pas besoin de le stocker, c'est tout ce qui compte.

Si toutefois vous avez besoin de mettre en cache l'interface "extraterre CoMarshalInterThreadInterfaceInStream/CoGetInterfaceAndReleaseStream:

Pour le stocker:

  • Entrez la section critique;
  • appel CoMarshalInterThreadInterfaceInStream et stocker le IStream pointeur dans un champ membre;
  • Laisser la section critique;

Pour le récupérer

  • Entrez la section critique;
  • appel CoGetInterfaceAndReleaseStream Pour récupérer l'interface
  • appel CoMarshalInterThreadInterfaceInStream et rangez-le à nouveau comme IStream pour toute utilisation future
  • Laisser la section critique;
  • Utilisez l'interface dans la portée de l'appel actuel

Pour le libérer:

  • Lorsque vous n'avez plus besoin de le garder, libérez simplement le stocké IStream (à l'intérieur de la section critique).

Si l'objet "extraterre CoGetInterfaceAndReleaseStream. Cependant, vous ne devez faire aucune hypothèse, et vous n'avez vraiment pas besoin de savoir si l'objet avec lequel vous traitez est l'objet d'origine ou un proxy de maréchauffer com.

Cela peut être légèrement optimisé en utilisant CoMarshalInterface avec MSHLFLAGS_TABLESTRONG / CoUnmarshalInterface / IStream::Seek(0, 0) / CoReleaseMarshalData à la place de CoGetInterfaceAndReleaseStream/CoGetInterfaceAndReleaseStream, pour désarracher la même interface que de nombreuses fois que nécessaire sans libérer le flux.

Des scénarios de mise en cache plus complexes (et peut-être plus efficaces) sont possibles, impliquant un stockage local de fil. Cependant, je crois que ce serait un exagéré. Je n'ai fait aucun moment, mais je pense que les frais généraux CoMarshalInterThreadInterfaceInStream/CoGetInterfaceAndReleaseStreamest vraiment bas.

Cela dit, si vous avez besoin de maintenir un état qui Stocke toutes les ressources ou objets qui peuvent nécessiter une affinité thread, à part les interfaces COM susmentionnées, vous ne devrait pas Marquez votre objet comme ThreadingModel=Both ou agréger le FTM.

Oui, le rassemblement est toujours possible. Quelques exemples:

  1. L'objet est instancié à partir d'un fil MTA et donc placé dans un appartement MTA, puis son pointeur est transmis dans n'importe quel thread STA et que le thread STA appelle les méthodes de l'objet. Dans ce cas, un thread STA ne peut accéder qu'à l'objet via le marshalling.

  2. L'objet est instancié à partir d'un fil STA et donc placé dans un appartement STA appartenant à ce fil, puis son pointeur est passé dans un autre fil STA ou un fil MTA. Dans les deux cas, ces threads ne peuvent accéder qu'à l'objet via le maréchalage.

En fait, vous ne pouvez vous attendre à ce que ce soit uniquement dans les deux cas suivants:

  1. L'objet est instancié à partir d'un thread MTA, puis accessible uniquement par les threads MTA - à la fois celui qui a instancié l'objet et tous les autres threads MTA du même processus.
  2. L'objet est instancié à partir d'un thread STA, puis accessible par ce fil même

Et dans tous les autres cas, le marshalling va entrer en jeu.

ThreadingModel = les deux signifie simplement que l'auteur du serveur COM peut donner une garantie que son code est une file d'attente mais ne peut pas donner la même garantie que autre Le code qu'il n'a pas écrit sera appelé de manière filée. Le cas le plus courant pour faire en sorte que ce code étranger s'exécute est par rappel, les points de connexion étant l'exemple le plus courant (généralement appelé "événements" dans les temps du client).

Donc, si l'instance de serveur a été créée dans un STA, le programmeur client va s'attendre à ce que les événements s'exécutent sur ce même thread. Même si une méthode de serveur qui tire un tel événement a été appelée à partir d'un autre thread. Cela nécessite que cet appel soit rassemblé.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top