Apartamentos Multithreaded

Em um modelo de apartamento multithreaded, todos os threads no processo que foram inicializados como free-threaded residem em um único apartamento. Portanto, não há necessidade de marechal entre fios. Os threads não precisam recuperar e despachar mensagens porque COM não usa mensagens de janela neste modelo.

Chamadas para métodos de objetos no apartamento multithreaded podem ser executadas em qualquer thread no apartamento. Não há serialização de chamadas; Muitas chamadas podem ocorrer para o mesmo método ou para o mesmo objeto simultaneamente. Os objetos criados no apartamento multithreaded devem ser capazes de lidar com chamadas em seus métodos de outros threads a qualquer momento.

Como as chamadas para objetos não são serializadas de forma alguma, a simultaneidade de objetos multithread oferece o mais alto desempenho e aproveita melhor o hardware multiprocessador para chamadas entre threads, entre processos e entre máquinas. Isso significa, no entanto, que o código para objetos deve fornecer sincronização em suas implementações de interface, normalmente por meio do uso de primitivas de sincronização, como objetos de evento, seções críticas, mutexes ou semáforos, que são descritos posteriormente nesta seção. Além disso, como o objeto não controla o tempo de vida dos threads que estão acessando-o, nenhum estado específico do thread pode ser armazenado no objeto (no armazenamento local do thread).

A seguir estão algumas considerações importantes sobre a sincronização para apartamentos multithread:

  • COM fornece sincronização de chamadas apenas para apartamentos de thread único.
  • Apartamentos multithreaded não recebem chamadas ao fazer chamadas (no mesmo thread).
  • Os apartamentos multithreaded não podem fazer chamadas sincronizadas com entrada.
  • As chamadas assíncronas são convertidas em chamadas síncronas em apartamentos multithread.
  • O filtro de mensagem não é chamado para nenhum thread em um apartamento multithreaded.

Para inicializar um thread como free-threaded, chame CoInitializeEx, especificando COINIT_MULTITHREADED. Para obter informações sobre threading de servidor em processo, consulte Problemas de threading de servidor em processo.

Vários clientes podem chamar simultaneamente, de diferentes threads, um objeto que ofereça suporte a threading livre. Em servidores fora de processo de thread livre, COM, por meio do subsistema RPC, cria um pool de threads no processo do servidor e uma chamada de cliente (ou várias chamadas de cliente) pode ser entregue por qualquer um desses threads a qualquer momento. Um servidor fora de processo também deve implementar a sincronização em sua fábrica de classes. Objetos em processo de thread livre podem receber chamadas diretas de vários threads do cliente.

O cliente pode fazer o trabalho COM em vários threads. Todos os threads pertencem ao mesmo apartamento multithreaded. Os ponteiros de interface são passados diretamente de thread para thread dentro de um apartamento multithreaded, para que os ponteiros de interface não sejam empacotados entre seus threads. Filtros de mensagem (implementações de IMessageFilter) não são usados em apartamentos multithreaded. O thread do cliente será suspenso quando fizer uma chamada COM para objetos fora do apartamento e será retomado quando a chamada retornar. As chamadas entre processos ainda são tratadas pelo RPC.

Os threads inicializados com o modelo de thread livre devem implementar sua própria sincronização. Conforme mencionado anteriormente nesta seção, o Windows habilita essa implementação por meio das seguintes primitivas de sincronização:

  • Os objetos de evento fornecem uma maneira de sinalizar um ou mais threads de que um evento ocorreu. Qualquer thread dentro de um processo pode criar um objeto de evento. Um identificador para o evento é retornado pela função de criação de eventos, CreateEvent. Depois que um objeto de evento é criado, os threads com um identificador para o objeto podem aguardar nele antes de continuar a execução.
  • As seções críticas são usadas para uma seção de código que requer acesso exclusivo a algum conjunto de dados compartilhados antes que ele possa ser executado e que é usado apenas pelos threads dentro de um único processo. Uma seção crítica é como uma catraca pela qual apenas uma rosca de cada vez pode passar, funcionando da seguinte maneira:
    • Para garantir que não mais de um thread por vez acesse dados compartilhados, o thread primário de um processo aloca uma estrutura de dados de CRITICAL_SECTION global e inicializa seus membros. Um thread que entra em uma seção crítica chama a função EnterCriticalSection e modifica os membros da estrutura de dados.
    • Um thread tentando entrar em uma seção crítica chama EnterCriticalSection que verifica se a estrutura de dados CRITICAL_SECTION foi modificada. Em caso afirmativo, outro thread está atualmente na seção crítica e o thread subsequente é colocado em suspensão. Um thread que sai de uma seção crítica chama LeaveCriticalSection, que redefine a estrutura de dados. Quando um thread sai de uma seção crítica, o sistema ativa um dos threads em suspensão, que então entra na seção crítica.
  • Mutexes executa a mesma função que uma seção crítica, exceto que o mutex é acessível a threads em execução em processos diferentes. Possuir um objeto mutex é como ter a palavra em um debate. Um processo cria um objeto mutex chamando a função CreateMutex , que retorna um identificador. O primeiro thread solicitando um objeto mutex obtém a propriedade dele. Quando o thread terminar com o mutex, a propriedade passa para outros threads por ordem de chegada.
  • Os semáforos são usados para manter uma contagem de referência em algum recurso disponível. Um thread cria um semáforo para um recurso chamando a função CreateSemaphore e passando um ponteiro para o recurso, uma contagem inicial de recursos e a contagem máxima de recursos. Essa função retorna um identificador. Um thread solicitando um recurso passa seu identificador de semáforo em uma chamada para a função WaitForSingleObject. O objeto semáforo sonda o recurso para determinar se ele está disponível. Em caso afirmativo, o semáforo diminui a contagem de recursos e ativa o fio de espera. Se a contagem for zero, o thread permanecerá suspenso até que outro thread libere um recurso, fazendo com que o semáforo incremente a contagem para um.

Acessando interfaces entre apartamentos

Escolhendo o modelo de threading

Problemas de threading do servidor em processo

Processos, threads e apartamentos

Comunicação Single-Threaded e Multithreaded

Apartamentos Single-Threaded