Partilhar via


Problemas de threading do In-Process Server

Um servidor em processo não chama CoInitialize, CoInitializeEx, ou OleInitialize para marcar o seu modelo de threading. Para objetos baseados em DLL com reconhecimento de thread ou objetos em processo, é necessário definir o modelo de thread no Registro. O modelo padrão quando você não especifica um modelo de threading é single-thread-per-process. Para especificar um modelo, adicione o valor ThreadingModel à chave InprocServer32 no registo.

DLLs que suportam instanciação de um objeto de classe devem implementar e exportar as funções DllGetClassObject e DllCanUnloadNow. Quando um cliente deseja uma instância da classe que a DLL suporta, uma chamada para CoGetClassObject (diretamente ou por meio de uma chamada para CoCreateInstance) chama DllGetClassObject para obter um ponteiro para seu objeto de classe quando o objeto é implementado em uma DLL. DllGetClassObject deve, portanto, ser capaz de fornecer vários objetos de classe ou um único objeto thread-safe (essencialmente usando apenas InterlockedIncrement/InterlockedDecrement em suas contagens de referência internas).

Como o próprio nome indica, DllCanUnloadNow é chamado para determinar se a DLL que o implementa está em uso, permitindo que o chamador o descarregue com segurança se não estiver. As chamadas para CoFreeUnusedLibraries de qualquer thread são sempre encaminhadas através da thread do apartamento principal para chamar DllCanUnloadNow.

Como outros servidores, os servidores em processamento podem ser de único segmento, de segmento por apartamento, ou de segmento livre. Esses servidores podem ser usados por qualquer cliente OLE, independentemente do modelo de threading usado por esse cliente.

Todas as combinações de interoperabilidade do modelo de threading são permitidas entre clientes e objetos em processo. A interação entre um cliente e um objeto em processo que usa modelos de threading diferentes é exatamente como a interação entre clientes e servidores fora do processo. Para um servidor em processo, quando o modelo de threading do cliente e do servidor em processo diferem, o COM deve interpor-se entre o cliente e o objeto.

Quando um objeto em processo que suporta o modelo single-threaded é chamado simultaneamente por vários threads de um cliente, o COM não pode permitir que os threads do cliente acessem diretamente a interface do objeto - o objeto não foi projetado para esse acesso. Em vez disso, COM deve garantir que as chamadas sejam sincronizadas e feitas apenas pelo thread do cliente que criou o objeto. Portanto, COM cria o objeto no apartamento principal do cliente e requer que todos os outros apartamentos do cliente acessem o objeto usando proxies.

Quando um apartamento de threads livres (modelo de apartamento multithread) num cliente cria um servidor em processo com threads de apartamento, o COM inicia um host de modelo de apartamento de thread único no cliente. Esse thread de host criará o objeto e o ponteiro da interface será empacotado de volta ao apartamento de thread livre do cliente. Da mesma forma, quando um apartamento de thread único em um cliente de modelo de apartamento cria um servidor em processo de multithread, o COM inicia um thread de host multithread (apartamento multithread no qual o objeto será criado e, em seguida, reencaminhado para o apartamento de thread único do cliente).

Observação

Em geral, se você projetar uma interface personalizada em um servidor em processo, você também deve fornecer o código de empacotamento para ele para que o COM possa organizar a interface entre os apartamentos do cliente.

 

COM ajuda a proteger o acesso a objetos fornecidos por uma DLL de único thread, exigindo acesso do mesmo ambiente cliente em que foram criados. Além disso, todos os pontos de entrada DLL (como DllGetClassObject e DllCanUnloadNow) e dados globais devem ser sempre acessados pelo mesmo apartamento. COM cria tais objetos no apartamento principal do cliente, proporcionando ao apartamento principal acesso direto aos ponteiros do objeto. As chamadas dos outros apartamentos usam o marshaling interthread para ir do proxy para o stub no apartamento principal e, em seguida, para o objeto. Isso permite que o COM sincronize chamadas para o objeto. As chamadas Interthread são lentas, por isso é recomendável que esses servidores sejam reescritos para suportar vários apartamentos.

Tal como um servidor de processo único em thread, um objeto fornecido por uma DLL de modelo de apartamento deve ser acedido pelo mesmo apartamento cliente a partir do qual foi criado. No entanto, os objetos fornecidos por este servidor podem ser criados em vários apartamentos do cliente, portanto, o servidor deve implementar seus pontos de entrada (como DllGetClassObject e DllCanUnloadNow) para uso multithreaded. Por exemplo, se dois apartamentos de um cliente tentarem criar duas instâncias do objeto em processo simultaneamente, DllGetClassObject poderá ser chamada simultaneamente por ambos os apartamentos. DllCanUnloadNow deve ser escrito para que a DLL não seja descarregada enquanto o código ainda está em execução na DLL.

Se a DLL fornecer apenas uma instância da fábrica de classes para criar todos os objetos, a implementação da fábrica de classes também deve ser projetada para uso multifiado, pois será acedida por vários apartamentos de cliente. Se a DLL criar uma nova instância da fábrica de classes cada vez que DllGetClassObject for chamado, a fábrica de classes não precisará ser thread-safe.

Os objetos criados pela fábrica de classes não precisam ser thread-safe. Uma vez criado por um thread, o objeto é sempre acessado através desse thread e todas as chamadas para o objeto são sincronizadas por COM. O apartamento modelo de um cliente que cria este objeto obterá um ponteiro direto para o objeto. Os apartamentos de clientes que são diferentes do apartamento em que o objeto foi criado devem acessar o objeto por meio de proxies. Estes proxies são criados quando o cliente controla a interface entre os seus apartamentos.

Quando uma DLL em processo valor de ThreadingModel é definida como "Both", um objeto fornecido por essa DLL pode ser criado e usado diretamente (sem um proxy) em apartamentos de cliente single-threaded ou multithreaded. No entanto, ele pode ser usado diretamente apenas dentro do apartamento em que foi criado. Para transferir o objeto para qualquer outro apartamento, o objeto deve ser processado. O objeto DLL deve implementar a sua própria sincronização e pode ser acedido por vários apartamentos de cliente ao mesmo tempo.

Para acelerar o desempenho do acesso de thread livre a objetos DLL em processo, o COM fornece a função CoCreateFreeThreadedMarshaler. Essa função cria um objeto de marshaling de thread livre que pode ser agregado a um objeto de servidor em processo. Quando um apartamento cliente no mesmo processo precisa de acesso a um objeto em outro apartamento, a agregação do empacotador de threads livres fornece ao cliente um ponteiro direto para o objeto do servidor, em vez de um proxy, quando o cliente repassa a interface do objeto para um apartamento diferente. O cliente não precisa fazer nenhuma sincronização. Isso funciona apenas dentro do mesmo processo; o marshaling padrão é usado para referenciar o objeto enviado para outro processo.

Um objeto fornecido por uma DLL em processo que suporta apenas threading livre é um objeto de thread livre. Ele implementa sua própria sincronização e pode ser acessado por vários threads de cliente ao mesmo tempo. Este servidor não intermedia interfaces entre threads; portanto, este servidor pode ser criado e usado diretamente (sem um proxy) apenas por apartamentos de múltiplas threads num cliente. Os apartamentos single-threaded que o criarem irão aceder a ele por meio de um proxy.

Acesso a interfaces entre apartamentos

Escolhendo o modelo de execução em threads

Apartamentos Multiencadeados

Processos, Threads e Apartamentos

Single-Threaded e Comunicação Multitarefa

Single-Threaded Apartamentos