Partilhar via


Objetos Semáforos

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

O objeto semáforo é útil no controle de um recurso compartilhado que pode suportar 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. Utiliza 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 semáforo em chamada para uma das funções de espera antes de cada janela ser criada. Quando a contagem é zero, indicando que o limite da janela foi atingido, a função de espera bloqueia a execução do código de criação da janela.

Um thread usa o CreateSemaphore ou função CreateSemaphoreEx para criar um objeto 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 inferior a zero nem superior ao valor máximo. O thread de criação também pode especificar um nome para o objeto semáforo. Threads em outros processos podem abrir um identificador para um objeto semáforo existente especificando seu nome em uma chamada para a funçãoOpenSemaphore. 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 em um semáforo, um thread de espera será selecionado. Não assuma uma ordem FIFO (first-in, first-out). Eventos externos, como APCs de 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 é diminuída em um. A função ReleaseSemaphore aumenta a contagem de um semáforo em uma quantidade especificada. A contagem nunca pode ser inferior a zero ou superior ao valor máximo.

A contagem inicial de um semáforo é normalmente definida para o valor máximo. A contagem é então diminuída a partir 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 até o valor máximo.

Um thread que possui um objeto mutex pode esperar repetidamente que o mesmo objeto mutex seja sinalizado sem que sua execução seja bloqueada. Um fio que espera repetidamente pelo mesmo objeto semáforo, no entanto, diminui a contagem do semáforo cada vez que uma operação de espera é concluída; O thread é bloqueado quando a contagem chega a zero. Da mesma forma, apenas 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 semáforo.

Um thread pode diminuir a contagem de um semáforo mais de uma vez, especificando repetidamente o mesmo objeto 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árias alças do mesmo semáforo não resulta em vários decréscimos.

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

Usando objetos Semaphore