Objetos Semaphore

Um objeto de semáforo é um objeto de sincronização que mantém uma contagem entre zero e um valor máximo especificado. A contagem é decrementada sempre que um thread conclui uma espera pelo objeto de semáforo e incrementada sempre que um thread libera o semáforo. Quando a contagem atinge zero, nenhum thread pode esperar com êxito para que o estado do objeto de semáforo seja sinalizado. O estado de um semáforo é definido como sinalizado quando a contagem é maior que zero e não sinalizado quando a contagem é zero.

O objeto semáforo é útil para controlar um recurso compartilhado que pode dar suporte a um número limitado de usuários. Ele atua como uma porta que limita o número de threads que compartilham o recurso a um número máximo especificado. Por exemplo, um aplicativo pode colocar um limite no número de janelas que ele cria. Ele usa um semáforo com uma contagem máxima igual ao limite da janela, diminuindo a contagem sempre que uma janela é criada e incrementando-a sempre que uma janela é fechada. O aplicativo especifica o objeto de semáforo na chamada para uma das funções de espera antes de cada janela ser criada. Quando a contagem for zero, indicando que o limite da janela foi atingido, a função de espera bloqueará a execução do código de criação de janela.

Um thread usa a função CreateSemaphore ou CreateSemaphoreEx para criar um objeto de semáforo. O thread de criação especifica a contagem inicial e o valor máximo da contagem para o objeto. A contagem inicial não deve ser menor que zero nem maior que o valor máximo. O thread de criação também pode especificar um nome para o objeto de semáforo. Threads em outros processos podem abrir um identificador para um objeto de semáforo existente especificando seu nome em uma chamada para a função OpenSemaphore . Para obter informações adicionais sobre nomes para objetos mutex, evento, semáforo e temporizador, consulte Sincronização entre processos.

Se mais de um thread estiver aguardando um semáforo, um thread de espera será selecionado. Não suponha uma ordem FIFO (primeiro a entrar, primeiro a sair). Eventos externos, como APCs no modo kernel, podem alterar a ordem de espera.

Cada vez que uma das funções de espera retorna porque o estado de um semáforo foi definido como sinalizado, a contagem do semáforo é reduzida em um. A função ReleaseSemaphore aumenta a contagem de um semáforo em um valor especificado. A contagem nunca pode ser menor que zero ou maior que o valor máximo.

A contagem inicial de um semáforo normalmente é definida como o valor máximo. A contagem é então decrementada desse nível à medida que o recurso protegido é consumido. Como alternativa, você pode criar um semáforo com uma contagem inicial de zero para bloquear o acesso ao recurso protegido enquanto o aplicativo está sendo inicializado. Após a inicialização, você pode usar ReleaseSemaphore para incrementar a contagem para o valor máximo.

Um thread que possui um objeto mutex pode esperar repetidamente para que o mesmo objeto mutex seja sinalizado sem que sua execução seja bloqueada. Um thread que aguarda repetidamente pelo mesmo objeto de semáforo, no entanto, diminui a contagem do semáforo sempre que uma operação de espera é concluída; o thread é bloqueado quando a contagem chega a zero. Da mesma forma, somente o thread que possui um mutex pode chamar com êxito a função ReleaseMutex , embora qualquer thread possa usar ReleaseSemaphore para aumentar a contagem de um objeto de semáforo.

Um thread pode diminuir a contagem de um semáforo mais de uma vez especificando repetidamente o mesmo objeto de semáforo em chamadas para qualquer uma das funções de espera. No entanto, chamar uma das funções de espera de vários objetos com uma matriz que contém vários identificadores do mesmo semáforo não resulta em vários decrementos.

Quando terminar de usar o objeto semáforo, chame a função CloseHandle para fechar o identificador. O objeto de semáforo é destruído quando seu último identificador é fechado. Fechar o identificador não afeta a contagem de semáforos; portanto, certifique-se de chamar ReleaseSemaphore antes de fechar o identificador ou antes que o processo seja encerrado. Caso contrário, as operações de espera pendentes terão um tempo limite ou continuarão indefinidamente, dependendo se um valor de tempo limite foi especificado.

Usando objetos Semaphore