web-dev-qa-db-fra.com

Appel de pthread_cond_signal sans verrouiller mutex

J'ai lu quelque part que nous devrions verrouiller le mutex avant d'appeler pthread_cond_signal et déverrouiller le mutext après l'avoir appelé:

La routine pthread_cond_signal () est utilisée pour signaler (ou réveiller) un autre thread qui attend la variable de condition. Elle doit être appelée après le verrouillage de mutex et doit déverrouiller mutex pour que la routine pthread_cond_wait () se termine.

Ma question est: n'est-il pas OK d'appeler les méthodes pthread_cond_signal ou pthread_cond_broadcast sans verrouiller le mutex?

77
Meysam

Si vous ne verrouillez pas le mutex dans le chemin de code qui modifie la condition et les signaux, vous pouvez perdre des réveils. Considérez cette paire de processus:

Processus A:

pthread_mutex_lock(&mutex);
while (condition == FALSE)
    pthread_cond_wait(&cond, &mutex);
pthread_mutex_unlock(&mutex);

Processus B (incorrect):

condition = TRUE;
pthread_cond_signal(&cond);

Considérez ensuite cet entrelacement possible d'instructions, où condition commence par FALSE:

Process A                             Process B

pthread_mutex_lock(&mutex);
while (condition == FALSE)

                                      condition = TRUE;
                                      pthread_cond_signal(&cond);

pthread_cond_wait(&cond, &mutex);

condition est maintenant TRUE, mais le processus A est bloqué en attente de la variable de condition - il a manqué le signal de réveil. Si nous modifions le processus B pour verrouiller le mutex:

Processus B (correct):

pthread_mutex_lock(&mutex);
condition = TRUE;
pthread_cond_signal(&cond);
pthread_mutex_unlock(&mutex);

... alors ce qui précède ne peut pas se produire; le réveil ne sera jamais manqué.

(Notez que vous pouvez déplacer réellement la pthread_cond_signal() elle-même après la pthread_mutex_unlock(), mais cela peut entraîner moins planification optimale des threads, et vous avez nécessairement verrouillé le mutex déjà dans ce chemin de code en raison de la modification de la condition elle-même).

134
caf

Selon ce manuel:

Les fonctions pthread_cond_broadcast() ou pthread_cond_signal() peuvent être appelées par un thread, qu'il possède ou non actuellement le mutex qui les threads appelant pthread_cond_wait() ou pthread_cond_timedwait() se sont associés à la variable de condition pendant leurs attentes; cependant, si un comportement de planification prévisible est requis, ce mutex doit être verrouillé par le thread appelant pthread_cond_broadcast() ou pthread_cond_signal().

La signification de l'instruction comportement de planification prévisible a été expliquée par Dave Butenhof (auteur de Programmation avec les threads POSIX ) sur comp.programming.threads et est disponible ici .

46
icecrime

caf, dans votre exemple de code, le processus B modifie condition sans verrouiller d'abord le mutex. Si le processus B a simplement verrouillé le mutex pendant cette modification, puis déverrouillé le mutex avant d'appeler pthread_cond_signal, il n'y aurait pas de problème --- ai-je raison?

Je crois intuitivement que le caf position est correct: appeler pthread_cond_signal sans posséder le verrou mutex est une mauvaise idée. Mais caf's exemple n'est pas en fait une preuve à l'appui de cette position; c'est simplement une preuve à l'appui de la position beaucoup plus faible (pratiquement évidente) que c'est une mauvaise idée de modifier l'état partagé protégé par un mutex, sauf si vous avez verrouillé ce mutex en premier.

Quelqu'un peut-il fournir un exemple de code dans lequel l'appel pthread_cond_signal suivi par pthread_mutex_unlock donne un comportement correct, mais en appelant pthread_mutex_unlock suivi par pthread_cond_signal donne un comportement incorrect?

4
Quuxplusone