Pregunta

Esto se desencadena por otra pregunta.

Específicamente, tengo una clase en proceso com, que se define en el Registro CLSID como tener un ThreadingModel de Both.

Nuestro proceso activa este objeto a través de CoCreateInstance (no CoCreateInstanceEx, si eso es importante para un servidor DLL en PROC)

Dado un modelo de enhebrado de Bothy dadas las reglas enumeradas en el documentos:

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

Y dado lo que Hans escribe en la otra respuesta:

... El mariscal ocurre cuando la llamada del cliente debe hacerse en un hilo diferente. ... puede suceder cuando el Modelo de Threading especificado en el elemento COMCLASS lo exige. En otras palabras, cuando el objeto COM se creó en un hilo, pero se llama en otro y el servidor no es seguro de subprocesos.

Mi conclusión tentativa sería que tal objeto nunca Necesita el ensarjamiento implícito de las llamadas a sus interfaces, ya que el objeto siempre vivirá en el mismo apartamento que su cliente.

Es eso correcto, incluso si el proceso del cliente se está ejecutando como Sta?

¿Fue útil?

Solución

Sí, puede haber mariscal.

Si el cliente de su clase COM se está ejecutando en un STA e intenta invocar su clase desde otro apartamento, tendrá que organizar el apartamento en el que fue creado.

La terminología COM puede ser realmente confusa. Cuando se refiere a un 'cliente' en este caso, realmente se refiere a un hilo, no a la aplicación completa (como implicaría).

Both Solo significa que el modelo de roscado del servidor se ajusta al cliente que lo instancia. Es decir, cuando instancías tu clase, toma el modelo de subproceso del hilo en el que se creó. Dado que está instanciando el servidor en un STA, su servidor usará STA, lo que significa que solo se puede invocar en el hilo que lo creó; Si otro hilo intenta invocarlo, marcará el hilo en el que se creó.

Otros consejos

No puedo evitar publicar esto, aunque no es una respuesta directa a la pregunta.

Hay un brillante artículo de MSKB de las edades doradas de com: Información: descripciones y funcionamiento de los modelos de subprocesos OLE. Todavía allí, y tiene toda la información relevante. El punto es que no debes preocuparte por si hay mariscal o no, si sigues las reglas. Simplemente registre su objeto como ThreadingModel=Both, agregue el mariscal de hilo libre con CoCreateFreeThreadedMarshaler, y terminar. Com hará el mariscal si es necesario, de la mejor manera posible. Dependiendo del modelo de apartamento del cliente, el código del cliente puede recibir el puntero directo a su interfaz, si también sigue las reglas.

Cualquier interfaz "alienígena" que pueda recibir cuando se llame a un método de su interfaz será válida en el alcance de la llamada, porque permanece en el mismo hilo. Si no necesita almacenarlo, eso es todo lo que importa.

Sin embargo, si necesita almacenar en caché la interfaz "Alien", la forma correcta de hacerlo sería almacenarla usando CoMarshalInterThreadInterfaceInStream/CoGetInterfaceAndReleaseStream:

Para almacenarlo:

  • Ingrese la sección crítica;
  • llamar CoMarshalInterThreadInterfaceInStream y almacenar el IStream puntero en un campo miembro;
  • Dejar la sección crítica;

Para recuperarlo

  • Ingrese la sección crítica;
  • llamar CoGetInterfaceAndReleaseStream Para recuperar la interfaz
  • llamar CoMarshalInterThreadInterfaceInStream y guárdelo de nuevo como IStream Para cualquier uso futuro
  • Dejar la sección crítica;
  • Use la interfaz en el alcance de la llamada actual

Para liberarlo:

  • Cuando ya no necesite mantenerlo, simplemente suelte el almacenado IStream (Dentro de la sección crítica).

Si el objeto "alienígena" también es libre, y las cosas están sucediendo dentro del mismo proceso, es probable que se ocupe de un puntero de interfaz directa después de CoGetInterfaceAndReleaseStream. Sin embargo, no debe hacer ninguna suposición, y realmente no necesita saber si el objeto con el que se trata es el objeto original o un proxy de com Marshaller.

Esto puede optimizarse ligeramente usando CoMarshalInterface w/ MSHLFLAGS_TABLESTRONG / CoUnmarshalInterface / IStream::Seek(0, 0) / CoReleaseMarshalData en vez de CoGetInterfaceAndReleaseStream/CoGetInterfaceAndReleaseStream, para desamar la misma interfaz tantas veces como sea necesario sin liberar la transmisión.

Los escenarios de almacenamiento de almacenamiento más complejos (y posiblemente más eficientes) son posibles, que involucran el almacenamiento local de subprocesos. Sin embargo, creo que sería una exageración. No hice ningún momento, pero creo que la sobrecarga de CoMarshalInterThreadInterfaceInStream/CoGetInterfaceAndReleaseStreames realmente bajo.

Dicho esto, si necesita mantener un estado que almacena cualquier recurso u objeto que pueda requerir afinidad de subprocesos, aparte de las interfaces com antes mencionadas, no debe Marque su objeto como ThreadingModel=Both o agregar el FTM.

Sí, el mariscal todavía es posible. Un par de ejemplos:

  1. El objeto se instancia desde un hilo MTA y, por lo tanto, se coloca en un apartamento MTA y luego su puntero se pasa a cualquier hilo STA y ese hilo STA llama a los métodos del objeto. En este caso, un hilo STA solo puede acceder al objeto a través de Marshalling.

  2. El objeto se instancia desde un hilo STA y, por lo tanto, se coloca en un apartamento STA que pertenece a ese hilo y luego su puntero se pasa a otro hilo STA o un hilo MTA. En ambos casos, esos hilos solo pueden acceder al objeto a través de Marshalling.

De hecho, no puede esperar no tener en cuenta solo en los siguientes dos casos:

  1. El objeto se instancia desde un hilo MTA y luego solo accede por hilos MTA, tanto el que instanció el objeto como en todos los demás hilos MTA del mismo proceso.
  2. El objeto se instancia desde un hilo STA y luego solo se accede por ese mismo hilo

Y en todos los demás casos, el mariscal se activará.

ThreadingModel = ambos simplemente significa que el autor del servidor COM puede garantizar que su código es seguro de hilo pero no puede dar la misma garantía de que otro El código que no escribió se llamará de manera segura. El caso más común para que se ejecute dicho código extranjero es a través de devoluciones de llamada, siendo los puntos de conexión el ejemplo más común (generalmente llamado "eventos" en los tiempos de ejecución del cliente).

Entonces, si la instancia del servidor se creó en un STA, el programador del cliente esperará que los eventos se ejecuten en ese mismo hilo. Incluso si se llamó a un método de servidor que dispara dicho evento desde otro hilo. Eso requiere que ese llamado sea organizado.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top