Funções de espera

As funções de espera permitem que um thread bloqueie sua própria execução. As funções de espera não retornam até que os critérios especificados sejam atendidos. O tipo de função de espera determina o conjunto de critérios usados. Quando uma função de espera é chamada, ela verifica se os critérios de espera foram atendidos. Se os critérios não tiverem sido atendidos, o thread de chamada entrará no estado de espera até que as condições dos critérios de espera sejam atendidas ou o intervalo de tempo limite especificado se especifique.

Funções de espera de objeto único

As funções SignalObjectAndWait, WaitForSingleObject e WaitForSingleObjectEx exigem um identificador para um objeto de sincronização. Essas funções retornam quando ocorre um dos seguintes procedimentos:

  • O objeto especificado está no estado sinalizado.
  • O intervalo de tempo limite passa. O intervalo de tempo limite pode ser definido como INFINITE para especificar que a espera não terá tempo limite.

A função SignalObjectAndWait permite que o thread de chamada defina atomicamente o estado de um objeto como sinalizado e aguarde até que o estado de outro objeto seja definido como sinalizado.

Funções de espera de vários objetos

As funções WaitForMultipleObjects, WaitForMultipleObjectsEx, MsgWaitForMultipleObjects e MsgWaitForMultipleObjectsEx permitem que o thread de chamada especifique uma matriz que contém um ou mais identificadores de objeto de sincronização. Essas funções retornam quando ocorre um dos seguintes procedimentos:

  • O estado de qualquer um dos objetos especificados é definido como sinalizado ou os estados de todos os objetos foram definidos como sinalizados. Você controla se um ou todos os estados serão usados na chamada de função.
  • O intervalo de tempo limite passa. O intervalo de tempo limite pode ser definido como INFINITE para especificar que a espera não terá tempo limite.

A função MsgWaitForMultipleObjects e MsgWaitForMultipleObjectsEx permite que você especifique objetos de evento de entrada na matriz do identificador de objeto. Isso é feito quando você especifica o tipo de entrada a ser aguardado na fila de entrada do thread. Por exemplo, um thread pode usar MsgWaitForMultipleObjects para bloquear sua execução até que o estado de um objeto especificado tenha sido definido como sinalizado e haja entrada do mouse disponível na fila de entrada do thread. O thread pode usar a função GetMessage ou PeekMessageA ou PeekMessageW para recuperar a entrada.

Ao aguardar que os estados de todos os objetos sejam definidos como sinalizados, essas funções de vários objetos não modificam os estados dos objetos especificados até que os estados de todos os objetos tenham sido definidos como sinalizados. Por exemplo, o estado de um objeto mutex pode ser sinalizado, mas o thread de chamada não obtém a propriedade até que os estados dos outros objetos especificados na matriz também tenham sido definidos como sinalizados. Enquanto isso, algum outro thread pode obter a propriedade do objeto mutex, definindo assim seu estado como não atribuído.

Ao aguardar que o estado de um único objeto seja definido como sinalizado, essas funções de vários objetos marcar os identificadores na matriz para começar com o índice 0, até que um dos objetos seja sinalizado. Se vários objetos forem sinalizados, a função retornará o índice do primeiro identificador na matriz cujo objeto foi sinalizado.

Funções de espera alertáveis

As funções MsgWaitForMultipleObjectsEx, SignalObjectAndWait, WaitForMultipleObjectsEx e WaitForSingleObjectEx diferem das outras funções de espera, pois, opcionalmente, podem executar uma operação de espera alertável. Em uma operação de espera alertável, a função pode retornar quando as condições especificadas são atendidas, mas também pode retornar se o sistema enfileirar uma rotina de conclusão de E/S ou um APC para execução pelo thread de espera. Para obter mais informações sobre operações de espera alertáveis e rotinas de conclusão de E/S, consulte Sincronização e entrada e saída sobrepostas. Para obter mais informações sobre APCs, consulte Chamadas de procedimento assíncrono.

Funções de espera registradas

A função RegisterWaitForSingleObject difere das outras funções de espera, pois a operação de espera é executada por um thread do pool de threads. Quando as condições especificadas são atendidas, a função de retorno de chamada é executada por um thread de trabalho do pool de threads.

Por padrão, uma operação de espera registrada é uma operação de espera múltipla. O sistema redefine o temporizador sempre que o evento é sinalizado (ou o intervalo de tempo limite passa) até que você chame a função UnregisterWaitEx para cancelar a operação. Para especificar que uma operação de espera deve ser executada apenas uma vez, defina o parâmetro dwFlags de RegisterWaitForSingleObject como WT_EXECUTEONLYONCE.

Se o thread chamar funções que usam APCs, defina o parâmetro dwFlags de RegisterWaitForSingleObject como WT_EXECUTEINPERSISTENTTHREAD.

Aguardando um endereço

Um thread pode usar a função WaitOnAddress para aguardar até que o valor de um endereço de destino seja alterado de algum valor indesejado para qualquer outro valor. Isso permite que os threads aguardem a alteração de um valor sem precisar girar ou lidar com os problemas de sincronização que podem surgir quando o thread captura um valor indesejado, mas o valor é alterado antes que o thread possa esperar.

WaitOnAddress retorna quando o código que modifica o valor de destino sinaliza a alteração chamando WakeByAddressSingle para ativar um único thread de espera ou WakeByAddressAll para ativar todos os threads em espera. Se um intervalo de tempo limite for especificado com WaitOnAddress e nenhum thread chamar uma função de ativação, a função retornará quando o intervalo de tempo limite decorrer. Se nenhum intervalo de tempo limite for especificado, o thread aguardará indefinidamente.

Funções de espera e intervalos de tempo limite

A precisão do intervalo de tempo limite especificado depende da resolução do relógio do sistema. O relógio do sistema "marca" a uma taxa constante. Se o intervalo de tempo limite for menor que a resolução do relógio do sistema, a espera poderá esgotar em menos do que o período de tempo especificado. Se o intervalo de tempo limite for maior que um tique, mas menor que dois, a espera poderá estar entre um e dois tiques e assim por diante.

Para aumentar a precisão do intervalo de tempo limite para as funções de espera, chame a função timeGetDevCaps para determinar a resolução mínima de temporizador com suporte e a função timeBeginPeriod para definir a resolução do temporizador como mínima. Tenha cuidado ao chamar timeBeginPeriod, pois chamadas frequentes podem afetar significativamente o relógio do sistema, o uso de energia do sistema e o agendador. Se você chamar timeBeginPeriod, chame-o uma vez no início do aplicativo e chame a função timeEndPeriod no final do aplicativo.

Funções de espera e objetos de sincronização

As funções de espera podem modificar os estados de alguns tipos de objetos de sincronização. A modificação ocorre apenas para o objeto ou objetos cujo estado sinalizado fez com que a função retornasse. As funções de espera podem modificar os estados dos objetos de sincronização da seguinte maneira:

  • A contagem de um objeto de semáforo diminui em um, e o estado do semáforo é definido como não atribuído se sua contagem for zero.
  • Os estados de mutex, evento de redefinição automática e objetos de notificação de alteração são definidos como não atribuídos.
  • O estado de um temporizador de sincronização é definido como não atribuído.
  • Os estados dos objetos de entrada de evento de redefinição manual, temporizador de redefinição manual, processo, thread e console não são afetados por uma função de espera.

Funções de espera e criação do Windows

Você precisa ter cuidado ao usar as funções de espera e o código que criam janelas direta ou indiretamente. Se um thread criar janelas, ele deverá processar mensagens. As transmissões de mensagens são enviadas para todas as janelas do sistema. Se você tiver um thread que usa uma função de espera sem intervalo de tempo limite, o sistema terá deadlock. Dois exemplos de código que criam indiretamente janelas são DDE e a função CoInitialize . Portanto, se você tiver um thread que cria janelas, use MsgWaitForMultipleObjects ou MsgWaitForMultipleObjectsEx, em vez das outras funções de espera.