Compartir a través de


Descripciones y funcionamiento de los modelos de subproceso OLE

En este artículo se describen los modelos de subproceso OLE.

Versión original del producto: modelos de subprocesos OLE
Número de KB original: 150777

Resumen

Los objetos COM se pueden usar en varios subprocesos de un proceso. Los términos "Single- threaded Apartment" (STA) y "Multi-threaded Apartment" (MTA) se usan para crear un marco conceptual para describir la relación entre objetos y subprocesos, las relaciones de simultaneidad entre objetos, los medios por los que las llamadas de método se entregan a un objeto y las reglas para pasar punteros de interfaz entre subprocesos. Los componentes y sus clientes eligen entre los dos modelos de apartamento siguientes compatibles actualmente con COM:

  1. Modelo de apartamento de un solo subproceso (STA): uno o varios subprocesos de un proceso usan COM y las llamadas a objetos COM se sincronizan mediante COM. Las interfaces se serializarán entre subprocesos. Un caso degenerado del modelo de apartamento de un solo subproceso, donde solo un subproceso de un proceso determinado usa COM, se denomina modelo de subproceso único. Anteriormente, a veces se ha referido al modelo STA simplemente como el "modelo de apartamento".

  2. Modelo de apartamento multiproceso (MTA): uno o varios subprocesos usan COM y las llamadas a objetos COM asociados con el MTA se realizan directamente por todos los subprocesos asociados con el MTA sin ninguna interposición del código del sistema entre el autor de la llamada y el objeto. Dado que varios clientes simultáneos pueden llamar a objetos más o menos simultáneamente (simultáneamente en sistemas de varios procesadores), los objetos deben sincronizar su estado interno por sí mismos. Las interfaces no se serializarán entre subprocesos. Anteriormente, a veces se conocía a este modelo como el "modelo sin subprocesos".

  3. Tanto el modelo STA como el modelo MTA se pueden usar en el mismo proceso. Esto se conoce a veces como un proceso de "modelo mixto".

El MTA se presenta en NT 4.0 y está disponible en Windows 95 con DCOM95. El modelo STA existe en Windows NT 3.51 y Windows 95, así como EN NT 4.0 y Windows 95 con DCOM95.

Información general

Los modelos de subprocesos de COM proporcionan el mecanismo para los componentes que usan diferentes arquitecturas de subprocesos para trabajar conjuntamente. También proporcionan servicios de sincronización a componentes que los requieren. Por ejemplo, un único subproceso puede diseñar un objeto determinado para que solo lo llame un subproceso y no sincronice llamadas simultáneas desde clientes. Si varios subprocesos llaman simultáneamente a este objeto, se bloquea o produce errores. COM proporciona los mecanismos para tratar esta interoperabilidad de las arquitecturas de subprocesos.

Incluso los componentes compatibles con subprocesos suelen necesitar servicios de sincronización. Por ejemplo, los componentes que tienen una interfaz gráfica de usuario (GUI), como controles OLE/ActiveX, incrustaciones activas en contexto y documentos ActiveX, requieren sincronización y serialización de llamadas COM y mensajes de ventana. COM proporciona estos servicios de sincronización para que estos componentes se puedan escribir sin código de sincronización complejo.

Un "apartamento" tiene varios aspectos relacionados entre ellos. En primer lugar, es una construcción lógica para pensar en la simultaneidad, como cómo se relacionan los subprocesos con un conjunto de objetos COM. En segundo lugar, es un conjunto de reglas que los programadores deben obedecer para recibir el comportamiento de simultaneidad que esperan del entorno COM. Por último, es código proporcionado por el sistema que ayuda a los programadores a administrar la simultaneidad de subprocesos con respecto a los objetos COM.

El término "apartamento" proviene de una metáfora en la que un proceso se concibe como una entidad discreta, como un "edificio" que se subdivide en un conjunto de "configuraciones regionales" relacionadas pero diferentes denominadas "apartamentos". Un apartamento es un "contenedor lógico" que crea una asociación entre objetos y, en algunos casos, subprocesos. Los subprocesos no son apartamentos, aunque puede haber un único subproceso asociado lógicamente a un apartamento en el modelo STA. Los objetos no son apartamentos, aunque todos los objetos están asociados a uno y solo un apartamento. Pero los apartamentos son más que una construcción lógica; sus reglas describen el comportamiento del sistema COM. Si no se siguen las reglas de los modelos de apartamento, los objetos COM no funcionarán correctamente.

Más detalles

Un apartamento de un solo subproceso (STA) es un conjunto de objetos COM asociados a un subproceso determinado. Estos objetos se asocian al apartamento mediante la creación del subproceso o, más precisamente, que se expone primero al sistema COM (normalmente mediante serialización) en el subproceso. UNA STA se considera un lugar donde un objeto o un proxy "vive". Si otro apartamento debe tener acceso al objeto o proxy (en el mismo proceso o diferente), el puntero de interfaz debe serializarse en ese apartamento donde se crea un nuevo proxy. Si se siguen las reglas del modelo de apartamento, no se permiten llamadas directas de otros subprocesos en el mismo proceso en ese objeto; que infringiría la regla que todos los objetos de un apartamento determinado se ejecutan en un único subproceso. La regla existe porque la mayoría del código que se ejecuta en una STA no funcionarán correctamente si se ejecutan en subprocesos adicionales.

El subproceso asociado a un STA debe llamar a CoInitialize o CoInitializeEx(NULL, COINIT_APARTMENTTHREADED) y debe recuperar y enviar mensajes de ventana para que los objetos asociados reciban llamadas entrantes. COM envía y sincroniza las llamadas a objetos de un STA mediante mensajes de ventana, como se describe más adelante en este artículo.

El "STA principal" es el subproceso que llama CoInitialize a o CoInitializeEx(NULL, COINIT_APARTMENTTHREADED) primero dentro de un proceso determinado. El STA principal de un proceso debe permanecer activo hasta que se complete todo el trabajo COM porque algunos objetos en proceso siempre se cargan en el STA principal, como se describe más adelante en este artículo.

Windows NT 4.0 y DCOM95 presentan un nuevo tipo de apartamento denominado apartamento multiproceso (MTA). Un MTA es un conjunto de objetos COM asociados a un conjunto de subprocesos en el proceso para que cualquier subproceso pueda llamar a cualquier implementación de objeto directamente sin la interposición del código del sistema. Los punteros de interfaz a cualquier objeto del MTA se pueden pasar entre los subprocesos asociados a MTA sin tener que serializarse. Todos los subprocesos del proceso que llaman CoInitializeEx(NULL, COINIT_MULTITHREADED) están asociados a MTA. A diferencia del STA descrito anteriormente, los subprocesos de un MTA no necesitan recuperar ni enviar mensajes de ventana para que los objetos asociados reciban llamadas entrantes. COM no sincroniza las llamadas a objetos de un MTA. Los objetos de un MTA deben proteger su estado interno frente a daños por la interacción de varios subprocesos simultáneos y no pueden hacer suposiciones sobre el contenido de Thread-Local Storage restante constante entre las distintas invocaciones de método.

Un proceso puede tener cualquier número de STA, pero, como máximo, puede tener un MTA. El MTA consta de uno o varios subprocesos. Los STA tienen un subproceso cada uno. Un subproceso pertenece, como máximo, a un apartamento. Los objetos pertenecen a uno y solo a un apartamento. Los punteros de interfaz siempre deben serializarse entre apartamentos (aunque el resultado de la serialización puede ser un puntero directo en lugar de un proxy). Vea la información siguiente sobre CoCreateFreeThreadedMarshaler.

Un proceso elige uno de los modelos de subprocesos proporcionados por COM. Un proceso de modelo STA tiene uno o varios STA y no tiene un MTA. Un proceso de modelo de MTA tiene un MTA con uno o varios subprocesos y no tiene ningún STA. Un proceso de modelo mixto tiene un MTA y cualquier número de STA.

Modelo de apartamento de un solo subproceso

El subproceso de una STA debe llamar a CoInitialize o CoInitializeEx(NULL, COINIT_APARTMENTTHREADED) y debe recuperar y enviar mensajes de ventana porque COM usa mensajes de ventana para sincronizar y enviar la entrega de llamadas a un objeto en este modelo. Consulte la sección REFERENCIAS a continuación para obtener más información.

Servidor que admite el modelo STA:

En el modelo STA, las llamadas a un objeto se sincronizan mediante COM de la misma manera que los mensajes de ventana publicados en una ventana se sincronizan. Las llamadas se entregan mediante mensajes de ventana al subproceso que creó el objeto . Por lo tanto, el subproceso del objeto debe llamar Get/PeekMessage a y DispatchMessage recibir llamadas. COM crea una ventana oculta asociada a cada STA. El tiempo de ejecución COM transfiere una llamada a un objeto desde fuera del STA al subproceso del objeto mediante un mensaje de ventana publicado en esta ventana oculta. Cuando el subproceso asociado al STA del objeto recupera y envía el mensaje, el procedimiento de ventana de la ventana oculta, también implementado por COM, lo recibe. El tiempo de ejecución de COM usa el procedimiento de ventana para "enlazar" el subproceso asociado a STA porque el tiempo de ejecución COM está en ambos lados de la llamada desde el subproceso propiedad de COM al subproceso de STA. El tiempo de ejecución COM (que ahora se ejecuta en el subproceso de STA) llama a "up" a través de un código auxiliar proporcionado por COM en el método de interfaz correspondiente del objeto. La ruta de acceso de ejecución que devuelve desde la llamada al método invierte la llamada "up"; La llamada vuelve al código auxiliar y al tiempo de ejecución COM, que pasa el control al subproceso en tiempo de ejecución COM a través de un mensaje de ventana, que luego vuelve a través del canal COM al autor de la llamada original.

Cuando varios clientes llaman a un objeto STA, las llamadas se ponen automáticamente en cola en la cola de mensajes mediante la transferencia del mecanismo de control usado en el STA. El objeto recibe una llamada cada vez que su STA recupera y envía mensajes. Dado que las llamadas se sincronizan mediante COM de esta manera y, dado que las llamadas siempre se entregan en el subproceso único asociado al STA del objeto, las implementaciones de interfaz del objeto no necesitan proporcionar sincronización.

Nota:

El objeto se puede volver a escribir si una implementación del método de interfaz recupera y envía mensajes mientras procesa una llamada al método, lo que hace que la misma STA entregue otra llamada al objeto. Una manera común en la que esto ocurre es si un objeto STA realiza una llamada de salida (entre apartamentos o entre procesos) mediante COM. Esto es idéntico a la manera en que se puede volver a escribir un procedimiento de ventana si recupera y envía mensajes mientras procesa un mensaje. COM no impide la entrada de nuevo en el mismo subproceso, pero evita la ejecución simultánea. También proporciona un medio por el que se puede administrar la reentrada relacionada con COM. Consulte la sección REFERENCIAS a continuación para obtener más información. El objeto no se vuelve a escribir si las implementaciones del método no llaman a su apartamento ni recuperan ni envían mensajes.

Responsabilidades del cliente en el modelo STA:

El código de cliente que se ejecuta en un proceso o subproceso que usa el modelo STA debe serializar interfaces de un objeto entre apartamentos mediante CoMarshalInterThreadInterfaceInStream y CoGetInterfaceAndReleaseStream. Por ejemplo, si Apartment 1 en el cliente tiene un puntero de interfaz y Apartment 2 requiere su uso, Apartment 1 debe serializar la interfaz mediante CoMarshalInterThreadInterfaceInStream. El objeto de secuencia devuelto por esta función es seguro para subprocesos y su puntero de interfaz debe almacenarse en una variable de memoria directa accesible por Apartment 2. El apartamento 2 debe pasar esta interfaz de secuencia para CoGetInterfaceAndReleaseStream desmarshalar la interfaz en el objeto subyacente y devolver un puntero a un proxy a través del cual puede tener acceso al objeto.

El apartamento principal de un proceso determinado debe permanecer activo hasta que el cliente haya completado todo el trabajo COM porque algunos objetos en proceso se cargan en el main-apartment. (A continuación se detalla más información).

Modelo de apartamento multiproceso

Una MTA es la colección de objetos creados o expuestos por todos los subprocesos del proceso que han llamado CoInitializeEx(NULL, COINIT_MULTITHREADED)a .

Nota:

Las implementaciones actuales de COM permiten que un subproceso que no inicialice COM explícitamente sea parte del MTA. Un subproceso que no inicializa COM forma parte del MTA solo si comienza a usar COM después de al menos otro subproceso en el proceso ha llamado CoInitializeEx(NULL, COINIT_MULTITHREADED)anteriormente a . (Incluso es posible que COM haya inicializado el MTA cuando ningún subproceso de cliente lo haya hecho explícitamente; por ejemplo, un subproceso asociado a una sta llama a CoGetClassObject/CoCreateInstance[Ex] en un CLSID marcado como "ThreadingModel=Free" y COM crea implícitamente un MTA en el que se carga el objeto de clase). Consulte la información sobre la interoperabilidad del modelo de subprocesos a continuación.

Sin embargo, se trata de una configuración que podría causar problemas, como infracciones de acceso, en determinadas circunstancias. Por lo tanto, se recomienda que cada subproceso que necesite realizar el trabajo COM inicialice COM llamando CoInitializeEx a y, a continuación, al finalizar el trabajo COM, llame a CoUninitialize. El costo de "innecesariamente" inicializar un MTA es mínimo.

Los subprocesos de MTA no necesitan recuperar y enviar mensajes porque COM no usa mensajes de ventana en este modelo para entregar llamadas a un objeto .

  • Servidor que admite el modelo MTA:

    En el modelo MTA, las llamadas a un objeto no se sincronizan mediante COM. Varios clientes pueden llamar simultáneamente a un objeto que admite este modelo en diferentes subprocesos y el objeto debe proporcionar sincronización en sus implementaciones de interfaz o método mediante objetos de sincronización como eventos, exclusión mutua, semáforos, etc. Los objetos MTA pueden recibir llamadas simultáneas de varios clientes fuera de proceso a través de un grupo de subprocesos creados por COM que pertenecen al proceso del objeto. Los objetos MTA pueden recibir llamadas simultáneas de varios clientes en proceso en varios subprocesos asociados a MTA.

  • Responsabilidades del cliente en el modelo MTA:

    El código de cliente que se ejecuta en un proceso o subproceso que usa el modelo MTA no tiene que serializar punteros de interfaz de un objeto entre sí y otros subprocesos de MTA. En su lugar, un subproceso de MTA puede usar un puntero de interfaz obtenido de otro subproceso de MTA como puntero de memoria directa. Cuando un subproceso de cliente realiza una llamada a un objeto fuera de proceso, se suspende hasta que se haya completado la llamada. Las llamadas pueden llegar a objetos asociados con el MTA, mientras que todos los subprocesos creados por la aplicación asociados a MTA se bloquean en las llamadas de salida. En este caso y en general, las llamadas entrantes se entregan en subprocesos proporcionados por el tiempo de ejecución COM. Los filtros de mensajes (IMessageFilter) no están disponibles para su uso en el modelo MTA.

Modelos de subprocesos mixtos

Un proceso que admita el modelo de subprocesos mixtos usará un MTA y uno o varios STA. Los punteros de interfaz deben serializarse entre todos los apartamentos, pero se pueden usar sin serializar dentro del MTA. Com sincroniza las llamadas a objetos de un STA para que se ejecuten solo en un subproceso mientras que las llamadas a objetos de MTA no lo son. Sin embargo, las llamadas de una STA a una MTA normalmente pasan por el código proporcionado por el sistema y cambian del subproceso STA a un subproceso de MTA antes de entregarse al objeto.

Nota:

Consulte la documentación del SDK en CoCreateFreeThreadedMarshaler() y la explicación de esa API siguiente para obtener información sobre los casos en los que se pueden usar punteros directos y cómo un subproceso STA puede llamar directamente a un objeto asociado primero con el MTA y, viceversa, desde varios apartamentos.

Elección de los modelos de subprocesos

Un componente puede optar por admitir el modelo STA, el modelo MTA o una combinación de los dos mediante el modelo de subproceso mixto. Por ejemplo, un objeto que realiza una E/S extensa puede optar por admitir MTA para proporcionar la respuesta máxima a los clientes al permitir que se realicen llamadas de interfaz durante la latencia de E/S. Como alternativa, un objeto que interactúa con el usuario casi siempre elige admitir STA para sincronizar las llamadas COM entrantes con sus operaciones de GUI. Admitir el modelo STA es más fácil porque COM proporciona sincronización. Admitir el modelo MTA es más difícil porque el objeto debe implementar la sincronización, pero la respuesta a los clientes es mejor porque la sincronización se usa para secciones de código más pequeñas, en lugar de para toda la llamada de interfaz, tal como lo proporciona COM.

El modelo STA también lo usa Microsoft Transaction Server (MTS, anteriormente denominado "Viper") y, por tanto, los objetos basados en DLL que planean ejecutarse en el entorno de MTS deben usar el modelo STA. Los objetos implementados para el modelo MTA normalmente funcionarán bien en un entorno de MTS. Sin embargo, se ejecutarán de forma menos eficaz porque usarán primitivos de sincronización de subprocesos innecesarios.

Marcar el modelo de subprocesos admitidos de los servidores en proceso

Un subproceso usa el modelo MTA si llama a CoInitializeEx(NULL, COINIT_MULTITHREADED) o usa COM sin inicializarlo. Un subproceso usa el modelo STA si llama a CoInitialize o CoInitializeEx(NULL, COINIT_APARTMENTTHREADED).

Las CoInitialize API proporcionan control de apartamento para el código de cliente y para los objetos empaquetados. EXE, ya que el código de inicio del entorno de ejecución de COM puede inicializar COM de la manera deseada.

Sin embargo, un servidor COM en proceso (basado en DLL) no llama a CoInitialize/CoInitializeEx porque esas API se han llamado por el momento en que se carga el servidor DLL. Por lo tanto, un servidor DLL debe usar el Registro para informar a COM del modelo de subprocesos que admite para que COM pueda asegurarse de que el sistema funciona de una manera compatible con él. Para este propósito se usa un valor con nombre de la clave ThreadingModel CLSID\InprocServer32 del componente, como se indica a continuación:

  • ThreadingModel valor no presente: admite el modelo de subproceso único.
  • ThreadingModel=Apartment: admite el modelo STA.
  • ThreadingModel=Both: admite el modelo STA y MTA.
  • ThreadingModel=Free: solo admite MTA.

Nota:

ThreadingModel es un valor con nombre, no una subclave de InprocServer32 como se documenta incorrectamente en algunas versiones anteriores de la documentación de Win32.

Los modelos de subprocesos de servidores en proceso se describen más adelante en este artículo. Si un servidor en proceso proporciona muchos tipos de objetos (cada uno con su propio CLSID único), cada tipo puede tener un valor diferente ThreadingModel . En otras palabras, el modelo de subprocesos es por CLSID, no por paquete de código o DLL. Sin embargo, los puntos de entrada de api necesarios para "arrancar" y consultar todos los servidores en proceso (, DLLCanUnloadNow()) deben ser seguros para subprocesos para cualquier servidor en proceso que admita varios subprocesos (DLLGetClassObject()lo que significa un ThreadingModel valor de Apartment, Both o Free).

Como se indicó anteriormente, los servidores fuera de proceso no se marcan mediante el valor threadingModel. En su lugar, usan CoInitialize o CoInitializeEx. Los servidores basados en DLL que esperan ejecutarse fuera de proceso mediante la funcionalidad "suplente" de COM (como el suplente proporcionado por el sistema DLLHOST.EXE) siguen las reglas para los servidores basados en DLL; no hay consideraciones especiales en ese caso.

Cuando el cliente y el objeto Usan modelos de subprocesos diferentes

La interacción entre un cliente y un objeto fuera de proceso es directa incluso cuando se usan diferentes modelos de subprocesos porque el cliente y el objeto están en procesos diferentes y COM está implicado en pasar llamadas del cliente al objeto. Dado que COM se interpone entre el cliente y el servidor, proporciona el código para la interoperación de los modelos de subprocesos. Por ejemplo, si varios clientes STA o MTA llaman simultáneamente a un objeto STA, COM sincroniza las llamadas colocando los mensajes de ventana correspondientes en la cola de mensajes del servidor. Sta del objeto recibe una llamada cada vez que recupera y envía mensajes. Todas las combinaciones de interoperabilidad del modelo de subprocesos se permiten y son totalmente compatibles entre los clientes y los objetos fuera de proceso.

La interacción entre un cliente y un objeto en proceso que usa modelos de subprocesos diferentes es más complicado. Aunque el servidor está en proceso, COM debe interponerse entre el cliente y el objeto en algunos casos. Por ejemplo, varios subprocesos de un cliente pueden llamar simultáneamente a un objeto en proceso diseñado para admitir el modelo STA. COM no puede permitir que los subprocesos de cliente accedan directamente a la interfaz del objeto porque el objeto no está diseñado para ese acceso simultáneo. En su lugar, COM debe asegurarse de que las llamadas están sincronizadas y realizadas solo por el subproceso asociado al STA que "contiene" el objeto. A pesar de la complejidad adicional, se permiten todas las combinaciones de interoperabilidad del modelo de subprocesos entre los clientes y los objetos en proceso.

Modelos de subprocesos en servidores fuera de proceso (basados en EXE)

A continuación se muestran tres categorías de servidores fuera de proceso, cada una de las cuales puede usar cualquier cliente COM independientemente del modelo de subproceso usado por ese cliente:

  1. Servidor de modelo STA:

    El servidor funciona com en uno o varios STA. Com sincroniza las llamadas entrantes y se entregan mediante el subproceso asociado al STA en el que se creó el objeto. Las llamadas al método class-factory se entregan mediante el subproceso asociado al STA que registró el generador de clases. El objeto y el generador de clases no necesitan implementar la sincronización. Sin embargo, el implementador debe sincronizar el acceso a las variables globales usadas por varios STA. El servidor debe usar CoMarshalInterThreadInterfaceInStream y CoGetInterfaceAndReleaseStream serializar punteros de interfaz, posiblemente de otros servidores, entre SLA. Opcionalmente, el servidor puede implementar IMessageFilter en cada STA para controlar aspectos de la entrega de llamadas por COM. Un caso degenerado es el servidor de modelo de subproceso único que funciona COM en una STA.

  2. Servidor de modelos MTA:

    El servidor funciona con COM en uno o varios subprocesos, todos los cuales pertenecen al MTA. Com no sincroniza las llamadas. COM crea un grupo de subprocesos en el proceso de servidor y cualquiera de estos subprocesos entrega una llamada de cliente. Los subprocesos no necesitan recuperar y enviar mensajes. El generador de objetos y clases debe implementar la sincronización. El servidor no necesita serializar punteros de interfaz entre subprocesos.

  3. Servidor de modelos mixtos:

    Consulte la sección de este artículo titulado "Modelo de subprocesos mixtos" para obtener más información.

Modelos de subprocesos en clientes

Hay tres categorías de clientes:

  1. Cliente del modelo STA:

    El cliente realiza trabajos COM en subprocesos asociados a uno o varios STA. El cliente debe usar CoMarshalInterThreadInterfaceInStream y CoGetInterfaceAndReleaseStream para serializar punteros de interfaz entre STA. Un caso degenerado es el cliente de modelo de subproceso único que funciona COM en una STA. El subproceso del cliente entra en un bucle de mensajes proporcionado por COM cuando realiza una llamada saliente. El cliente puede usar IMessageFilter para administrar devoluciones de llamada y procesamiento de mensajes de ventana mientras se esperan llamadas de salida y otros problemas de simultaneidad.

  2. Cliente del modelo MTA:

    El cliente funciona com en uno o varios subprocesos, todos los cuales pertenecen al MTA. El cliente no necesita serializar punteros de interfaz entre sus subprocesos. El cliente no puede usar IMessageFilter. Los subprocesos del cliente se suspenden cuando realizan una llamada COM a un objeto fuera de proceso y se reanudan cuando se devuelve la llamada. Las llamadas entrantes llegan a subprocesos creados por COM y administrados.

  3. Cliente de modelo mixto:

    Consulte la sección de este artículo titulado "Modelo de subprocesos mixtos" para obtener más información.

Modelos de subprocesos en servidores en proceso (basados en DLL)

Hay cuatro categorías de servidores en proceso, cada una de las cuales puede ser utilizada por cualquier cliente COM independientemente del modelo de subprocesos utilizado por ese cliente. Sin embargo, los servidores en proceso deben proporcionar código de serialización para cualquier interfaz personalizada (no definida por el sistema) que implementen si son compatibles con la interoperabilidad del modelo de subprocesos, ya que normalmente requiere que COM serializa la interfaz entre los apartamentos de cliente. Las cuatro categorías son:

  1. Servidor in-proc que admite subprocesos únicos ("main" STA)- sin ThreadingModel valor:

    Un objeto proporcionado por este servidor espera que el mismo STA de cliente al que se haya creado. Además, el servidor espera que el mismo subproceso acceda a todos sus puntos de entrada, como DllGetClassObject y DllCanUnloadNow, y los datos globales (el asociado al STA principal). Los servidores que existían antes de la introducción de subprocesos múltiples en COM se encuentran en esta categoría. Estos servidores no están diseñados para ser accesibles por varios subprocesos, por lo que COM crea todos los objetos proporcionados por el servidor en el STA principal del proceso y las llamadas a los objetos se entregan mediante el subproceso asociado al STA principal. Otros apartamentos cliente obtienen acceso al objeto a través de servidores proxy. Las llamadas de los otros apartamentos van desde el proxy al código auxiliar en el STA principal (serialización entre subprocesos) y, a continuación, al objeto . Esta serialización permite que COM sincronice las llamadas al objeto y las llamadas se entregan mediante el STA en el que se creó el objeto. La serialización entre subprocesos es lenta en relación con las llamadas directas, por lo que se recomienda que estos servidores se vuelvan a escribir para admitir varios STA (categoría 2).

  2. Servidor en proceso que admite el modelo de apartamento de un solo subproceso (varios STA): marcado con ThreadingModel=Apartment:

    Un objeto proporcionado por este servidor espera que el mismo STA de cliente al que se haya creado. Por lo tanto, es similar a un objeto proporcionado por un servidor en proceso de un solo subproceso. Sin embargo, los objetos proporcionados por este servidor se pueden crear en varios STA del proceso, por lo que el servidor debe diseñar sus puntos de entrada, como DllGetClassObject y DllCanUnloadNow, y datos globales para el uso multiproceso. Por ejemplo, si dos STA de un proceso crean dos instancias del objeto en proceso simultáneamente, DllGetClassObject ambas SLA pueden llamarse simultáneamente. Del mismo modo, DllCanUnloadNow debe escribirse para que el servidor esté protegido de descargarse mientras el código todavía se está ejecutando en el servidor.

    Si el servidor solo proporciona una instancia del generador de clases para crear todos los objetos, la implementación de generador de clases también debe diseñarse para el uso multiproceso porque varios STA de cliente acceden a ella. Si el servidor crea una nueva instancia del generador de clases cada vez DllGetClassObject que se llama a , la factoría de clases no necesita ser segura para subprocesos. Sin embargo, el implementador debe sincronizar el acceso a las variables globales.

    No es necesario que los objetos COM creados por el generador de clases sean seguros para subprocesos. Sin embargo, el implementador debe sincronizar el acceso de las variables globales. Una vez creado por un subproceso, siempre se accede al objeto a través de ese subproceso y todas las llamadas al objeto se sincronizan mediante COM. Los apartamentos de cliente que son diferentes del STA en el que se creó el objeto deben tener acceso al objeto a través de servidores proxy. Estos servidores proxy se crean cuando el cliente serializa la interfaz entre sus apartamentos.

    Cualquier cliente que cree un objeto STA a través de su generador de clases obtiene un puntero directo al objeto . Esto es diferente de los objetos de un solo subproceso en proceso, donde solo el STA principal del cliente obtiene un puntero directo al objeto y todos los demás STA que crean el objeto obtienen acceso al objeto a través de un proxy. Dado que la serialización entre subprocesos es lenta en relación con las llamadas directas, la velocidad se puede mejorar cambiando un servidor en proceso de un solo subproceso para admitir varios STA.

  3. Servidor en proceso que solo admite MTA: marcado con ThreadingModel=Free:

    Un objeto proporcionado por este servidor es seguro solo para el MTA. Implementa su propia sincronización y se accede a ella mediante varios subprocesos de cliente al mismo tiempo. Este servidor puede tener un comportamiento incompatible con el modelo STA. (Por ejemplo, por su uso de la cola de mensajes de Windows de una manera que interrumpe la bomba de mensajes de una STA). Además, marcando el modelo de subproceso del objeto como "Gratis", el implementador del objeto indica lo siguiente: este objeto se puede llamar desde cualquier subproceso de cliente, pero este objeto también puede pasar punteros de interfaz directamente (sin serializar) a los subprocesos que creó y estos subprocesos pueden realizar llamadas a través de estos punteros. Por lo tanto, si el cliente pasa un puntero de interfaz a un objeto implementado por el cliente (como un receptor) a este objeto, puede optar por volver a llamar a través de este puntero de interfaz desde cualquier subproceso que haya creado. Si el cliente es una STA, una llamada directa desde un subproceso, que es diferente del subproceso que creó el objeto receptor se producirá un error (como se muestra en 2 anteriores). Por lo tanto, COM siempre garantiza que los clientes de subprocesos asociados a una STA obtengan acceso a este tipo de objeto en proceso solo a través de un proxy. Además, estos objetos no deben agregarse con el serializador de subprocesos libre porque eso les permite ejecutarse directamente en subprocesos STA.

  4. Servidor en proceso que admite el modelo de apartamento y el subproceso libre, marcados con ThreadingModel=Both:

    Un objeto proporcionado por este servidor implementa su propia sincronización y varios apartamentos de cliente acceden simultáneamente a él. Además, este objeto se crea y se usa directamente, en lugar de a través de un proxy, en STAs o en el MTA de un proceso de cliente. Dado que este objeto se usa directamente en stAs, el servidor debe serializar interfaces de objetos, posiblemente de otros servidores, entre subprocesos, por lo que se garantiza su acceso a cualquier objeto de una manera adecuada para subprocesos. Además, marcando el modelo de subproceso del objeto como "Ambos", el implementador del objeto indica lo siguiente: este objeto se puede llamar desde cualquier subproceso de cliente, pero las devoluciones de llamada de este objeto al cliente solo se realizarán en el apartamento en el que el objeto recibió el puntero de interfaz al objeto de devolución de llamada. COM permite crear este tipo de objeto directamente en una STA, así como en un MTA del proceso de cliente.

    Dado que cualquier apartamento que crea este objeto siempre obtiene un puntero directo en lugar de un puntero proxy, ThreadingModel "Both" los objetos proporcionan mejoras de rendimiento sobre ThreadingModel "Free" los objetos cuando se cargan en una STA.

    Dado que un ThreadingModel "Both" objeto también está diseñado para el acceso A MTA (es seguro para subprocesos internamente), puede acelerar el rendimiento agregando con el serializador proporcionado por CoCreateFreeThreadedMarshaler. Este objeto proporcionado por el sistema se agrega a cualquier objeto de llamada y serializaciones personalizadas dirige punteros al objeto en todos los apartamentos del proceso. Los clientes de cualquier apartamento, ya sea sta o MTA, pueden tener acceso al objeto directamente en lugar de a través de un proxy. Por ejemplo, un cliente de modelo STA crea el objeto en proceso en STA1 y serializa el objeto en STA2. Si el objeto no se agrega con el serializador de subprocesos libre, STA2 obtiene acceso al objeto a través de un proxy. Si es así, el serializador de subprocesos libre proporciona STA2 con un puntero directo al objeto

    Nota:

    Se debe tener cuidado al agregar con el serializador de subprocesos libre. Por ejemplo, supongamos que un objeto que está marcado como ThreadingModel "Both" (y que también se agrega con el serializador de subprocesos libres) tiene un miembro de datos que es un puntero de interfaz a otro objeto cuyo ThreadingModel es "Apartment". A continuación, supongamos que una STA crea el primer objeto y, durante la creación, el primer objeto crea el segundo objeto. Según las reglas descritas anteriormente, el primer objeto ahora contiene un puntero directo al segundo objeto. Ahora supongamos que el STA serializa el puntero de interfaz al primer objeto a otro apartamento. Dado que el primer objeto se agrega con el serializador de subprocesos libre, se asigna un puntero directo al primer objeto al segundo apartamento. Si el segundo apartamento llama a través de este puntero y, si esta llamada hace que el primer objeto llame a través del puntero de interfaz al segundo objeto, se ha producido un error, porque el segundo objeto no está pensado para llamarse directamente desde el segundo apartamento. Si el primer objeto contiene un puntero a un proxy al segundo objeto en lugar de un puntero directo, esto provocará un error diferente. Los servidores proxy del sistema también son objetos COM asociados a uno y solo un apartamento. Realizan un seguimiento de su apartamento con el fin de evitar ciertas circularidades. Por lo tanto, un objeto que llama a en un proxy asociado a un apartamento diferente del subproceso en el que se ejecuta el objeto recibirá el RPC_E_WRONG_THREAD devolución del proxy y se producirá un error en la llamada.

Interoperabilidad del modelo de subprocesos entre clientes y objetos en proceso

Se permiten todas las combinaciones de interoperabilidad del modelo de subproceso entre los clientes y los objetos en proceso.

COM permite que todos los clientes del modelo STA interoperan con objetos de un solo subproceso en proceso mediante la creación y acceso al objeto en el STA principal del cliente y serializarlo en el STA de cliente que llamó CoCreateInstance[Ex]a .

Si un MTA de un cliente crea un servidor en proceso de modelo STA, COM pone en marcha un STA de "host" en el cliente. Este STA de host crea el objeto y el puntero de interfaz se serializa de nuevo en el MTA. De forma similar, cuando un STA crea un servidor en proceso de MTA, COM pone en marcha un MTA host en el que se crea el objeto y se serializa de nuevo en el STA. La interoperabilidad entre el modelo de subproceso único y el modelo MTA se controla de forma similar porque el modelo de subproceso único es simplemente un caso degenerado del modelo STA.

El código de serialización debe proporcionarse para cualquier interfaz personalizada que un servidor en proceso implemente si quiere admitir la interoperabilidad que requiere que COM serializa la interfaz entre los apartamentos de cliente. Consulte la sección REFERENCIAS a continuación para obtener más información.

Relación entre el modelo de subproceso y el objeto de generador de clases devueltos

En los dos pasos siguientes se explica una definición precisa de los servidores en proceso que se "cargan en" apartamentos:

  1. Si el cargador del sistema operativo no ha cargado previamente la dll que contiene la clase de servidor en proceso (asignada al espacio de direcciones del proceso), esa operación se realiza y COM obtiene la dirección de la DLLGetClassObject función exportada por el archivo DLL. Si el archivo DLL se ha cargado previamente mediante un subproceso asociado a cualquier apartamento, esta fase se omite.

  2. COM usa el subproceso (o, en el caso del MTA, uno de los subprocesos) asociado al apartamento "carga" para llamar a la DllGetClassObject función exportada por el archivo DLL que solicita el CLSID de la clase necesaria. A continuación, el objeto de fábrica devuelto se usa para crear instancias de objetos de la clase .

    El segundo paso (la llamada de DllGetClassObject por COM) se produce cada vez que un cliente llama CoGetClassObject/CoCreateIntance[Ex]a , incluso desde dentro del mismo apartamento. En otras palabras, DllGetClassObject un subproceso asociado al mismo apartamento puede llamarlo muchas veces; todo depende del número de clientes de ese apartamento que intentan obtener acceso a un objeto de generador de clases para esa clase.

Los autores de implementaciones de clase y, en última instancia, el autor del paquete DLL de un conjunto determinado de clases tiene plena libertad para decidir qué objeto de fábrica devolver en respuesta a la DllGetClassObject llamada de función. El autor del paquete DLL tiene la última palabra porque el código "detrás" del punto de entrada de todo DllGetClassObject() el archivo DLL es lo que tiene el derecho primero y potencialmente final para decidir qué hacer. Las tres posibilidades típicas son:

  1. DllGetClassObject devuelve un objeto de generador de clases único por subproceso de llamada (lo que significa un objeto de generador de clases por STA y potencialmente varias fábricas de clases dentro del MTA).

  2. DllGetClassObject siempre devuelve el mismo objeto generador de clases, independientemente de la identidad del subproceso que realiza la llamada o del tipo de apartamento asociado al subproceso que realiza la llamada.

  3. DllGetClassObject devuelve un objeto de generador de clases único por apartamento de llamada (uno por apartamento en STA y MTA).

Existen otras posibilidades para la relación entre las llamadas a DllGetClassObject y el objeto generador de clases devuelto (por ejemplo, un nuevo objeto de generador de clases por llamada a DllGetClassObject), pero actualmente no parecen ser útiles.

Resumen de los modelos de subproceso de objetos y cliente para servidores en proceso

En la tabla siguiente se resume la interacción entre diferentes modelos de subprocesos cuando un subproceso de cliente llama CoGetClassObject primero a una clase que se implementa como servidor en proceso.

Tipos de clientes o subprocesos:

  • el cliente se ejecuta en un subproceso asociado a la STA "main" (primer subproceso al que llamar CoInitialize o CoInitializeEx con COINIT_APARTMENTTHREADED la marca) llame a este STA0 (también denominado modelo de subproceso único).
  • El cliente se ejecuta en un subproceso asociado a en cualquier otro STA [ASCII 150] llamar a este STA*.
  • el cliente se ejecuta en un subproceso asociado a en el MTA.

Tipos de servidores DLL:

  • El servidor no tiene ninguna ThreadingModel clave: llame a "None".
  • El servidor está marcado como "Apartment"--call this "Apt".
  • El servidor está marcado como "Gratis".
  • El servidor está marcado como "Ambos".

Al leer la tabla siguiente, tenga en cuenta la definición anterior a la "carga" de un servidor en un apartamento.

Client         Server                 Result
STA0           None                   Direct access; server loaded into STA0  
STA*           None                   Proxy access; server loaded into STA0.  
MTA            None                   Proxy access; server loaded into STA0; STA0 created automatically by COM if necessary;  
STA0           Apt                    Direct access; server loaded into STA0  
STA*           Apt                    Direct access; server loaded into STA*  
MTA            Apt                    Proxy access; server loaded into an STA created automatically by COM.
STA0           Free                   Proxy access; server is loaded into MTA MTA created automatically by COM if necessary.
STA*           Free                   Same as STA0->Free
MTA            Free                   Direct access
STA0           Both                   Direct access; server loaded into STA0
STA*           Both                   Direct access; server loaded into STA*
MTA            Both                   Direct access; server loaded into the MTA

Referencias

Documentación del SDK en la CoRegisterMessageFilter() interfaz y IMessageFilter .