É assim que as variáveis de condição são (ou foram originalmente) implementadas.
O mutex é usado para proteger a própria variável de condição . É por isso que você precisa trancado antes de esperar.
A espera irá "atomicamente" desbloquear o mutex, permitindo que outros acessem a variável de condição (para sinalização). Então, quando a variável de condição for sinalizada ou transmitida para, um ou mais dos encadeamentos na lista de espera serão acordados e o mutex será magicamente bloqueado novamente para esse encadeamento.
Você geralmente vê a seguinte operação com variáveis de condição, ilustrando como elas funcionam. O exemplo a seguir é um thread de trabalho que recebe trabalho por meio de um sinal para uma variável de condição.
thread:
initialise.
lock mutex.
while thread not told to stop working:
wait on condvar using mutex.
if work is available to be done:
do the work.
unlock mutex.
clean up.
exit thread.
O trabalho é realizado dentro desse loop, desde que haja algum disponível quando a espera retornar. Quando o encadeamento for sinalizado para parar de fazer o trabalho (geralmente por outro encadeamento que define a condição de saída e depois chuta a variável de condição para ativar esse encadeamento), o loop será encerrado, o mutex será desbloqueado e o encadeamento será encerrado.
O código acima é um modelo de consumidor único, pois o mutex permanece bloqueado enquanto o trabalho está sendo feito. Para uma variação de vários consumidores, você pode usar, como exemplo :
thread:
initialise.
lock mutex.
while thread not told to stop working:
wait on condvar using mutex.
if work is available to be done:
copy work to thread local storage.
unlock mutex.
do the work.
lock mutex.
unlock mutex.
clean up.
exit thread.
o que permite que outros consumidores recebam trabalho enquanto este trabalha.
A variável de condição dispensa o ônus de pesquisar alguma condição, permitindo que outro encadeamento o notifique quando algo precisa acontecer. Outro segmento pode dizer a esse segmento que o trabalho está disponível da seguinte maneira:
lock mutex.
flag work as available.
signal condition variable.
unlock mutex.
A grande maioria do que muitas vezes é chamado erroneamente de despertar espúrio geralmente era sempre porque vários encadeamentos eram sinalizados em sua pthread_cond_wait
chamada (transmissão); um retornava com o mutex, fazia o trabalho e depois aguardava.
Em seguida, o segundo thread sinalizado poderia sair quando não havia trabalho a ser feito. Portanto, você precisava ter uma variável extra indicando que o trabalho deveria ser feito (isso era inerentemente protegido por mutex com o par condvar / mutex aqui - outros threads necessários para bloquear o mutex antes de alterá-lo).
Ele era tecnicamente possível para um thread para retornar de uma espera de condição sem ser expulso por outro processo (este é um verdadeiro despertar espúria), mas, em todos os meus muitos anos trabalhando em pthreads, tanto no desenvolvimento / serviço do código e como um usuário deles, nunca recebi um deles. Talvez tenha sido apenas porque a HP teve uma implementação decente :-)
De qualquer forma, o mesmo código que tratou do caso incorreto também tratou de ativações falsas genuínas, já que o sinalizador de trabalho disponível não seria definido para eles.