web-dev-qa-db-fra.com

compréhension de pthread_cond_wait () et pthread_cond_signal ()

De manière générale, pthread_cond_wait() et pthread_cond_signal() sont appelés comme suit:

//thread 1:
pthread_mutex_lock(&mutex);
pthread_cond_wait(&cond, &mutex);
do_something()
pthread_mutex_unlock(&mutex);

//thread 2:
pthread_mutex_lock(&mutex);
pthread_cond_signal(&cond);  
pthread_mutex_unlock(&mutex);

Les étapes sont

  1. pthread_cond_wait(&cond, &mutex); est appelée, elle déverrouille le mutex

  2. Le thread 2 verrouille le mutex et appelle pthread_cond_signal(), ce qui déverrouille le mutex

  3. Dans le thread 1, pthread_cond_wait() est appelée et verrouille à nouveau le mutex

Maintenant dans le thread 2, après l'appel de pthread_cond_signal(), pthread_mutex_unlock(&mutex) va s'exécuter, il me semble qu'il veut déverrouiller un mutex qui est maintenant verrouillé par le thread 1. Y a-t-il quelque chose de mal dans ma compréhension?

Par ailleurs, il me semble également que pthread_cond_wait() ne peut être appelée que par 1 thread pour la même paire cond-mutex. Mais il y a un dicton "La fonction pthread_cond_signal () doit débloquer au moins un des threads qui sont bloqués sur la variable de condition spécifiée cond (si des threads sont bloqués sur cond)." Donc, cela signifie que pthread_cond_wait() peut être appelée par plusieurs threads pour la même paire cond-mutex?

33
user1944267

pthread_cond_signal ne déverrouille pas le mutex (il ne peut pas car il n'a aucune référence au mutex, alors comment pourrait-il savoir quoi déverrouiller?) En fait, le signal n'a pas besoin d'avoir de connexion avec le mutex; le thread de signalisation n'a pas besoin de contenir le mutex, mais pour la plupart des algorithmes basés sur des variables de condition, il le fera.

pthread_cond_wait déverrouille le mutex juste avant son sommeil (comme vous le constatez), mais il réachète le mutex (ce qui peut nécessiter une attente) lorsqu'il est signalé, avant qu'il ne se réveille. Donc, si le thread de signalisation contient le mutex (le cas habituel), le thread en attente ne se poursuivra pas tant que le thread de signalisation ne déverrouillera pas également le mutex.

L'utilisation courante des vars de condition est quelque chose comme:

thread 1:
    pthread_mutex_lock(&mutex);
    while (!condition)
        pthread_cond_wait(&cond, &mutex);
    /* do something that requires holding the mutex and condition is true */
    pthread_mutex_unlock(&mutex);

thread2:
    pthread_mutex_lock(&mutex);
    /* do something that might make condition true */
    pthread_cond_signal(&cond);
    pthread_mutex_unlock(&mutex);

Les deux threads ont une structure de données partagée à laquelle le mutex protège l'accès. Le premier thread veut attendre qu'une condition soit vraie, puis effectuez immédiatement une opération (sans possibilité de condition de concurrence pour qu'un autre thread entre entre la vérification de condition et l'action et rend la condition fausse.) Le deuxième thread fait quelque chose qui pourrait rendre la condition vraie, il doit donc réveiller toute personne qui pourrait l'attendre.

75
Chris Dodd

Voici un exemple typique: le thread 1 attend une condition, qui peut être remplie par le thread 2 .

Nous utilisons un mutex et une condition.

pthread_mutex_t mutex;
pthread_cond_t condition;

fil 1:

pthread_mutex_lock(&mutex); //mutex lock
while(!condition){
    pthread_cond_wait(&condition, &mutex); //wait for the condition
}

/* do what you want */

pthread_mutex_unlock(&mutex);

fil 2:

pthread_mutex_lock(&mutex);

/* do something that may fulfill the condition */

pthread_mutex_unlock(&mutex);
pthread_cond_signal(&condition); //wake up thread 1

Modifier

Comme vous pouvez le voir dans le manuel pthread_cond_wait :

Il libère atomiquement mutex et provoque le blocage du thread appelant sur la variable de condition cond; atomiquement signifie ici "atomiquement par rapport à l'accès par un autre thread au mutex puis à la variable de condition".

7
Ludzu