Para citar a página do manual:
Ao usar variáveis de condição, sempre há um predicado booleano que envolve variáveis compartilhadas associadas a cada espera de condição que é verdadeira se o encadeamento continuar. Ativações espúrias das funções pthread_cond_timedwait () ou pthread_cond_wait () podem ocorrer. Como o retorno de pthread_cond_timedwait () ou pthread_cond_wait () não implica nada sobre o valor desse predicado, o predicado deve ser reavaliado com esse retorno.
Portanto, você pthread_cond_wait
pode retornar mesmo que não tenha sinalizado. À primeira vista, pelo menos, isso parece bastante atroz. Seria como uma função que retornasse aleatoriamente o valor errado ou retornasse aleatoriamente antes de realmente atingir uma declaração de retorno adequada. Parece um grande erro. Mas o fato de terem optado por documentar isso na página de manual, em vez de corrigi-lo, parece indicar que há uma razão legítima pela qualpthread_cond_wait
acorde espúrio. Presumivelmente, há algo intrínseco sobre como funciona que faz com que isso não possa ser ajudado. A questão é o que.
Por que pthread_cond_wait
retornar espuriosamente? Por que não pode garantir que só vai acordar quando for sinalizado corretamente? Alguém pode explicar a razão de seu comportamento espúrio?
pthread_cond_(timed)wait
: "Se um sinal for entregue ... o encadeamento continuará aguardando a variável de condição como se fosse interrompido ou retornará zero devido a despertar espúrio ". Outras funções de bloqueio indicamEINTR
quando interrompidas por um sinal (por exemploread
) ou são necessárias para retomar (por exemplopthread_mutex_lock
). Portanto, se não houvesse outras razões para despertar espúrio,pthread_cond_wait
poderia ter sido definido como qualquer uma dessas.Respostas:
A seguinte explicação é dada por David R. Butenhof em "Programando com Threads POSIX" (p. 80):
Na discussão comp.programming.threads a seguir , ele expande o pensamento por trás do design:
fonte
Há pelo menos duas coisas que "despertar espúrio" pode significar:
pthread_cond_wait
pode retornar da chamada, mesmo que não tenha ocorrido nenhuma chamadapthread_call_signal
oupthread_cond_broadcast
condição.pthread_cond_wait
retorna devido a uma chamada parapthread_cond_signal
oupthread_cond_broadcast
, no entanto, após recuperar o mutex, o predicado subjacente não é mais verdadeiro.Mas o último caso pode ocorrer mesmo se a implementação da variável de condição não permitir o caso anterior. Considere uma fila do consumidor produtor e três threads.
pthread_cond_wait
e os blocos na chamada que aguardam sinal / transmissão.Portanto, como você sempre precisa verificar o predicado em um loop, não faz diferença se as variáveis de condição subjacentes podem ter outros tipos de ativação espúria.
fonte
pthread_cond_signal/broadcast
e não poderá fazê-lo, até que o mutex seja desbloqueado ao chamarpthread_cond_wait
.A seção "Vários despertares por sinal de condição" em pthread_cond_signal possui um exemplo de implementação de pthread_cond_wait e pthread_cond_signal, que envolve despertares espúrios.
fonte
Embora eu não ache que foi considerado no momento do design, há uma razão técnica real: em combinação com o cancelamento de encadeamento, há condições sob as quais a opção de ativar "espuriosamente" pode ser absolutamente necessária, pelo menos, a menos que você está disposto a impor restrições muito fortes a que tipo de estratégias de implementação são possíveis.
O principal problema é que, se um encadeamento atua no cancelamento enquanto está bloqueado
pthread_cond_wait
, os efeitos colaterais devem ser como se não consumisse nenhum sinal na variável de condição. No entanto, é difícil (e altamente restritivo) garantir que você ainda não tenha consumido um sinal ao começar a agir no cancelamento e, nesse estágio, pode ser impossível "re-postar" o sinal na variável de condição, pois você pode estar em uma situação em que o chamador depthread_cond_signal
já está justificado por ter destruído o condvar e liberado a memória em que residia.A permissão para despertar espúrio oferece uma saída fácil. Em vez de continuar atuando no cancelamento quando chegar bloqueado em uma variável de condição, se você já tiver consumido um sinal (ou se quiser ser preguiçoso, não importa o quê), pode declarar que ocorreu uma ativação espúria, e volte com sucesso. Isso não interfere na operação do cancelamento, porque um chamador correto simplesmente age no cancelamento pendente na próxima vez que ele faz um loop e liga
pthread_cond_wait
novamente.fonte