Pergunta

Isso é desencadeado por outra pergunta.

Especificamente, eu tenho uma classe de processo com a classe, que é definida no CLSID Registry como tendo um ThreadingModel do Both.

Nosso processo ativa este objeto através CoCreateInstance (não CoCreateInstanceEx, se isso é importante para um servidor DLL no proco)

Dado um modelo de rosqueamento de Bothe dadas as regras listadas no documentos:

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

E dado o que Hans escreve na outra resposta:

... O marechaling ocorre quando a chamada do cliente precisa ser feita em um encadeamento diferente. ... pode acontecer quando o modelador de threadingModel especificado no elemento Comclass exige. Em outras palavras, quando o objeto COM foi criado em um thread, mas é chamado em outro e o servidor não é seguro para threads.

Minha conclusão provisória seria que esse objeto Nunca Precisa de um marechaling implícito de chamadas para suas interfaces, pois o objeto sempre viverá no mesmo apartamento que seu cliente.

Isso está correto, mesmo que o processo do cliente esteja em execução como Sta?

Foi útil?

Solução

Sim, pode haver organização.

Se o cliente da sua classe com que estiver em uma STA e você tentar invocar sua classe de outro apartamento, terá que marcar o apartamento em que foi criado.

A terminologia COM pode ser realmente confusa. Quando você se refere a um 'cliente' neste caso, você está realmente se referindo a um thread, não ao aplicativo inteiro (como implicaria).

Both Significa apenas que o modelo de encadeamento do servidor está em conformidade com o cliente que o instancia. Ou seja, quando você instancia sua classe, ele assume o modelo de rosqueamento do thread em que foi criado. Como você está instanciando o servidor em um STA, seu servidor usará o STA, o que significa que ele só pode ser chamado no thread que o criou; Se outro tópico tentar invocá -lo, ele marcará o tópico em que foi criado.

Outras dicas

Não posso deixar de postar isso, embora não seja uma resposta direta para a pergunta.

Há um brilhante artigo da MSKB da idade dourada de Com: Informações: Descrições e funcionamentos de modelos de encadeamento OLE. Ainda lá, e tem todas as informações relevantes. O ponto é que você não deve se preocupar se há marechaling ou não, se você seguir as regras. Basta registrar seu objeto como ThreadingModel=Both, agregar o marechaler de thread livre com CoCreateFreeThreadedMarshaler, e ser feito. Com fará o marechaling, se necessário, da melhor maneira possível. Dependendo do modelo de apartamento do cliente, o código do cliente pode receber o ponteiro direto da sua interface, se seguir as regras também.

Qualquer interface "alienígena" que você possa receber quando um método da sua interface for chamado será válido no escopo da chamada, porque você permanece no mesmo thread. Se você não precisa armazená -lo, isso é tudo o que importa.

Se, porém CoMarshalInterThreadInterfaceInStream/CoGetInterfaceAndReleaseStream:

Para armazená -lo:

  • Entrar na seção crítica;
  • ligar CoMarshalInterThreadInterfaceInStream e armazenar o IStream ponteiro em um campo membro;
  • Deixar seção crítica;

Para recuperá -lo

  • Entrar na seção crítica;
  • ligar CoGetInterfaceAndReleaseStream Para recuperar a interface
  • ligar CoMarshalInterThreadInterfaceInStream e armazená -lo novamente como IStream Para qualquer uso futuro
  • Deixar seção crítica;
  • Use a interface no escopo da chamada atual

Para lançar:

  • Quando você não precisa mais mantê -lo, basta liberar o armazenado IStream (dentro da seção crítica).

Se o objeto "alienígena" também for livre e as coisas estão acontecendo dentro do mesmo processo, você provavelmente estará lidando com um ponteiro de interface direto depois CoGetInterfaceAndReleaseStream. No entanto, você não deve fazer suposições e realmente não precisa saber se o objeto com o qual lidar é o objeto original ou um proxy do marshaller.

Isso pode ser um pouco otimizado usando CoMarshalInterface W/ MSHLFLAGS_TABLESTRONG / CoUnmarshalInterface / IStream::Seek(0, 0) / CoReleaseMarshalData ao invés de CoGetInterfaceAndReleaseStream/CoGetInterfaceAndReleaseStream, para solucionar a mesma interface quantas vezes o necessário sem liberar o fluxo.

Cenários de cache mais complexos (e possivelmente mais eficientes) são possíveis, envolvendo o armazenamento local. No entanto, acredito que isso seria um exagero. Eu não fiz nenhum tempo, mas acho que a sobrecarga de CoMarshalInterThreadInterfaceInStream/CoGetInterfaceAndReleaseStreamé realmente baixo.

Dito isto, se você precisar manter um estado que Armazra quaisquer recursos ou objetos que possam exigir afinidade do encadeamento, além de interfaces comi mencionadas, você não deveria Marque seu objeto como ThreadingModel=Both ou agregar o FTM.

Sim, o marechaling ainda é possível. Alguns exemplos:

  1. O objeto é instanciado a partir de um encadeamento MTA e, portanto, colocado em um apartamento MTA e, em seguida, seu ponteiro é passado para qualquer encadeamento STA e esse encadeamento STA chama métodos do objeto. Nesse caso, um thread STA pode acessar apenas o objeto por meio do marechalling.

  2. O objeto é instanciado a partir de um fio STA e, portanto, colocado em um apartamento STA pertencente a esse fio e, em seguida, seu ponteiro é passado para outro segmento STA ou uma rosca MTA. Nos dois casos, esses threads podem acessar apenas o objeto por meio do marechalling.

Na verdade, você não pode esperar que não seja marechaling apenas nos dois casos a seguir:

  1. O objeto é instanciado a partir de um encadeamento MTA e depois acessado apenas pelos threads MTA - tanto o que instanciou o objeto e todos os outros threads MTA do mesmo processo.
  2. O objeto é instanciado de um segmento STA e depois acessado apenas por esse tópico

E em todos os outros casos, o marechaling entrará em ação.

ThreadingModel = Ambos significa simplesmente que o autor do servidor COM pode garantir que seu código seja seguro, mas não pode dar a mesma garantia que outro Código que ele não escreveu será chamado de maneira segura por threads. O caso mais comum de obter um código estrangeiro a ser executado é através de retornos de chamada, sendo os pontos de conexão o exemplo mais comum (geralmente chamado de "eventos" no cliente de execução do cliente).

Portanto, se a instância do servidor foi criada em um STA, o programador do cliente esperará que os eventos sejam executados no mesmo thread. Mesmo que um método de servidor que atire esse evento tenha sido chamado de outro thread. Isso exige que essa chamada seja organizada.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top