Objetos de seção crítica
Um objeto de seção crítica fornece sincronização semelhante à fornecida por um objeto mutex, exceto que uma seção crítica pode ser usada apenas pelos threads de um único processo. Os objetos de seção crítica não podem ser compartilhados entre processos.
Os objetos de evento, mutex e semáforo também podem ser usados em um aplicativo de processo único, mas os objetos de seção crítica fornecem um mecanismo um pouco mais rápido e eficiente para sincronização de exclusão mútua (uma instrução de teste e conjunto específica do processador). Como um objeto mutex, um objeto de seção crítica pode pertencer a apenas um thread de cada vez, o que o torna útil para proteger um recurso compartilhado de acesso simultâneo. Ao contrário de um objeto mutex, não há como saber se uma seção crítica foi abandonada.
A partir do Windows Server 2003 com Service Pack 1 (SP1), os threads que aguardam em uma seção crítica não adquirem a seção crítica por ordem de chegada. Essa alteração aumenta significativamente o desempenho para a maioria dos códigos. No entanto, alguns aplicativos dependem da ordem FIFO (first-in, first-out) e podem ter um desempenho insatisfatório ou não ter nenhum desempenho nas versões atuais do Windows (por exemplo, aplicativos que têm usado seções críticas como um limitador de taxa). Para garantir que seu código continue a funcionar corretamente, talvez seja necessário adicionar um nível adicional de sincronização. Por exemplo, suponha que você tenha um thread de produtor e um thread de consumidor que estejam usando um objeto de seção crítica para sincronizar seu trabalho. Crie dois objetos de evento, um para cada thread usar para sinalizar que está pronto para o outro thread prosseguir. O thread do consumidor aguardará que o produtor sinalize seu evento antes de entrar na seção crítica, e o thread do produtor aguardará que o thread do consumidor sinalize seu evento antes de entrar na seção crítica. Depois que cada thread sai da seção crítica, ele sinaliza seu evento para liberar o outro thread.
Windows Server 2003 e Windows XP: Threads que estão aguardando em uma seção crítica são adicionados a uma fila de espera; Eles são acordados e geralmente adquirem a seção crítica na ordem em que foram adicionados à fila. No entanto, se os threads forem adicionados a essa fila em uma taxa rápida o suficiente, o desempenho poderá ser prejudicado devido ao tempo que leva para despertar cada thread em espera.
O processo é responsável por alocar a memória usada por uma seção crítica. Normalmente, isso é feito simplesmente declarando uma variável do tipo CRITICAL_SECTION. Antes que os threads do processo possam usá-lo, inicialize a seção crítica usando o InitializeCriticalSection ou função de InitializeCriticalSectionAndSpinCount.
Um thread usa o EnterCriticalSection ou função de TryEnterCriticalSection para solicitar a propriedade de uma seção crítica. Ele usa a funçãoLeaveCriticalSection para liberar a propriedade de uma seção crítica. Se o objeto de seção crítica for atualmente de propriedade de outro thread, EnterCriticalSection aguardará indefinidamente pela propriedade. Por outro lado, quando um objeto mutex é usado para exclusão mútua, as funções de espera aceitam um intervalo de tempo limite especificado. A função TryEnterCriticalSection tenta entrar em uma seção crítica sem bloquear o thread de chamada.
Quando um thread possui uma seção crítica, ele pode fazer chamadas adicionais para EnterCriticalSection ou TryEnterCriticalSection sem bloquear sua execução. Isso evita que um thread se bloqueie enquanto aguarda uma seção crítica que ele já possui. Para liberar sua propriedade, o thread deve chamar LeaveCriticalSection uma vez para cada vez que entrou na seção crítica. Não há garantia sobre a ordem em que os threads de espera adquirirão a propriedade da seção crítica.
Um thread usa o InitializeCriticalSectionAndSpinCount ou função SetCriticalSectionSpinCount para especificar uma contagem de rotação para o objeto de seção crítica. Girar significa que quando um thread tenta adquirir uma seção crítica que está bloqueada, o thread entra em um loop, verifica se o bloqueio está liberado e, se o bloqueio não for liberado, o thread entra em suspensão. Em sistemas de processador único, a contagem de rotação é ignorada e a contagem de rotação da seção crítica é definida como 0 (zero). Em sistemas multiprocessadores, se a seção crítica não estiver disponível, o thread de chamada gira dwSpinCount vezes antes de executar uma operação de espera em um semáforo associado à seção crítica. Se a seção crítica ficar livre durante a operação de rotação, o thread de chamada evitará a operação de espera.
Qualquer thread do processo pode usar a funçãoDeleteCriticalSection para liberar os recursos do sistema que são alocados quando o objeto de seção crítica é inicializado. Depois que essa função é chamada, o objeto de seção crítica não pode ser usado para sincronização.
Quando um objeto de seção crítica é de propriedade, os únicos outros threads afetados são os threads que estão aguardando a propriedade em uma chamada para EnterCriticalSection. Os threads que não estão esperando estão livres para continuar sendo executados.
Tópicos relacionados