Compartilhar via


Auxiliares de implementação de servidor fora de processo

Quatro funções auxiliares que podem ser chamadas por servidores fora de processo estão disponíveis para simplificar o trabalho de gravação do código do servidor. Clientes COM e servidores COM em processo normalmente não os chamariam. Essas funções são projetadas para ajudar a evitar condições de corrida na ativação do servidor quando os servidores têm vários apartamentos ou vários objetos de classe. Eles também podem, no entanto, ser facilmente usados para servidores de objetos de classe única e de thread único. As funções são as seguintes:

Para desligar corretamente, um servidor COM deve acompanhar quantas instâncias de objeto ele instanciou e quantas vezes seu método IClassFactory::LockServer foi chamado. Somente quando ambas as contagens atingirem zero um servidor poderá ser desligado. Em servidores COM de thread único, a decisão de desligar foi coordenada com solicitações de ativação de entrada, que foram serializadas pela fila de mensagens. O servidor, ao receber uma versão em sua instância de objeto final e decidir desligar, revogaria seus objetos de classe antes que mais solicitações de ativação fossem expedidas. Se uma solicitação de ativação chegou após esse ponto, COM reconheceria que os objetos de classe foram revogados e retornaria um erro ao SCM (Service Control Manager), o que faria com que uma nova instância do processo do servidor local fosse executada.

No entanto, em um servidor de modelo de apartamento, no qual diferentes objetos de classe são registrados em apartamentos diferentes e em todos os servidores com thread livre, essa decisão de desligar deve ser coordenada com solicitações de ativação em vários threads para que um thread do servidor não decida desligar enquanto outro thread do servidor estiver ocupado distribuindo objetos de classe ou instâncias de objeto. Uma abordagem clássica, mas complicada, para resolver isso é fazer com que o servidor, depois de revogar seus objetos de classe, verifique novamente sua contagem de instâncias e permaneça vivo até que todas as instâncias sejam liberadas.

Para tornar mais fácil para os gravadores de servidor lidar com esses tipos de condições de corrida, o COM fornece duas funções de contagem de referência:

Quando a contagem global de referência por processo atinge zero, o COM chama automaticamente CoSuspendClassObjects, o que impede a entrada de novas solicitações de ativação. O servidor pode então desregistificar seus vários objetos de classe de seus vários threads no lazer sem se preocupar que outra solicitação de ativação possa entrar. Todas as novas solicitações de ativação são tratadas de agora em diante pelo SCM iniciando uma nova instância do processo de servidor local.

A maneira mais simples de um aplicativo de servidor local usar essas funções é chamar CoAddRefServerProcess no construtor para cada um de seus objetos de instância e em cada um de seus métodos IClassFactory::LockServer quando o parâmetro fLock é VERDADEIRO. O aplicativo de servidor também deve chamar CoReleaseServerProcess no destruidor de cada um de seus objetos de instância e em cada um de seus métodos IClassFactory::LockServer quando o parâmetro fLock é false.

Por fim, o aplicativo de servidor deve prestar atenção ao código de retorno de CoReleaseServerProcesse, se retornar 0, o aplicativo de servidor deverá iniciar sua limpeza, o que, para um servidor com vários threads, normalmente significa que ele deve sinalizar seus vários threads para sair de seus loops de mensagem e chamar CoAddRefServerProcess e CoReleaseServerProcess. Se as funções de gerenciamento de tempo de vida do processo do servidor forem usadas, elas deverão ser usadas nas instâncias de objeto e no métodoLockServer; caso contrário, o aplicativo de servidor pode ser desligado prematuramente.

Quando uma solicitaçãoCoGetClassObjectfor feita, o COM contatará o servidor, realizará marshaling da interfaceIClassFactorydo objeto de classe, retornará ao processo do cliente, cancelará a gravação da interface IClassFactory e retornará isso ao cliente. Neste ponto, os clientes normalmente chamam lockServer com verdadeiro para impedir que o processo do servidor seja desligado. No entanto, há uma janela de tempo entre quando o objeto de classe é marshalado e quando o cliente chama LockServer em que outro cliente pode se conectar ao mesmo servidor, obter uma instância e liberar essa instância, fazendo com que o servidor seja desligado e deixando o primeiro cliente alto e seco com um ponteiro IClassFactory desconectado. Para evitar essa condição de corrida, COM adiciona uma chamada implícita para LockServer com TRUE ao objeto de classe quando ele faz marshaling da interface IClassFactory e uma chamada implícita para LockServer com FALSE quando o cliente libera a interface IClassFactory. Portanto, não é necessário fazer chamadas remotas LockServer para o servidor e o proxy para LockServer simplesmente retorna S_OK sem, na verdade, a comunicação remota da chamada.

Há outra condição de corrida relacionada à ativação durante a inicialização de um processo de servidor fora de processo. Um servidor COM que registra várias classes normalmente chama CoRegisterClassObject com REGCLS_LOCAL_SERVER para cada CLSID compatível. Depois de fazer isso para todas as classes, o servidor insere seu loop de mensagem. Para um servidor COM com thread único, todas as solicitações de ativação são bloqueadas até que o servidor insira o loop de mensagem. No entanto, para um servidor de modelo de apartamento que registra objetos de classe diferentes em apartamentos diferentes e para todos os servidores com thread livre, as solicitações de ativação podem chegar mais cedo do que isso. No caso de servidores de modelo de apartamento, as solicitações de ativação podem chegar assim que qualquer thread tiver inserido seu loop de mensagem. No caso de servidores com thread livre, uma solicitação de ativação pode chegar assim que o objeto de primeira classe for registrado. Como uma ativação pode acontecer tão cedo, também é possível que a versão final ocorra (e, portanto, faça com que o servidor comece a desligar) antes que o restante do servidor tenha a chance de concluir a inicialização.

Para eliminar essas condições de corrida e simplificar o trabalho do gravador de servidor, qualquer servidor que queira registrar vários objetos de classe com COM deve chamar CoRegisterClassObject com REGCLS_LOCAL_SERVER | REGCLS_SUSPENDED para cada CLSID diferente que o servidor dá suporte. Depois que todas as classes tiverem sido registradas e o processo de servidor estiver pronto para aceitar solicitações de ativação de entrada, o servidor deverá fazer uma chamada para CoResumeClassObjects. Essa função informa ao COM para informar o SCM sobre todas as classes registradas e começa a permitir solicitações de ativação no processo do servidor. O uso dessas funções fornece as seguintes vantagens:

  • Somente uma chamada é feita ao SCM, independentemente de quantos CLSIDs estão registrados, reduzindo assim o tempo de registro geral (e, portanto, o tempo de inicialização do aplicativo do servidor).
  • Se o servidor tiver vários apartamentos e CLSIDs diferentes estiverem registrados em apartamentos diferentes ou se o servidor for um servidor com thread livre, nenhuma solicitação de ativação entrará até que o servidor chame CoResumeClassObjects, dando ao servidor a chance de registrar todos os seus CLSIDs e ser configurado corretamente antes de ter que lidar com solicitações de ativação e possíveis solicitações de desligamento.

de responsabilidades do servidor COM