97 votes

Dois-je acquérir un verrou avant d'appeler condition_variable.notify_one() ?

Je suis un peu confus quant à l'utilisation de std::condition_variable . Je comprends que je dois créer un unique_lock sur un mutex avant d'appeler condition_variable.wait() . Ce que je ne trouve pas, c'est si je dois également acquérir un verrou unique avant d'appeler notify_one() o notify_all() .

Exemples sur cppreference.com sont contradictoires. Par exemple, le notify_une page donne cet exemple :

#include <iostream>
#include <condition_variable>
#include <thread>
#include <chrono>

std::condition_variable cv;
std::mutex cv_m;
int i = 0;
bool done = false;

void waits()
{
    std::unique_lock<std::mutex> lk(cv_m);
    std::cout << "Waiting... \n";
    cv.wait(lk, []{return i == 1;});
    std::cout << "...finished waiting. i == 1\n";
    done = true;
}

void signals()
{
    std::this_thread::sleep_for(std::chrono::seconds(1));
    std::cout << "Notifying...\n";
    cv.notify_one();

    std::unique_lock<std::mutex> lk(cv_m);
    i = 1;
    while (!done) {
        lk.unlock();
        std::this_thread::sleep_for(std::chrono::seconds(1));
        lk.lock();
        std::cerr << "Notifying again...\n";
        cv.notify_one();
    }
}

int main()
{
    std::thread t1(waits), t2(signals);
    t1.join(); t2.join();
}

Ici, la serrure n'est pas acquise pour la première notify_one() mais il est acquis pour la deuxième notify_one() . En regardant d'autres pages avec des exemples, je vois différentes choses, la plupart n'acquérant pas la serrure.

  • Est-ce que je peux choisir moi-même de verrouiller le mutex avant d'appeler notify_one() et pourquoi je choisirais de la fermer ?
  • Dans l'exemple donné, pourquoi n'y a-t-il pas de verrouillage pour le premier notify_one() mais il y en a pour les appels ultérieurs. Cet exemple est-il erroné ou y a-t-il une justification ?

0voto

Ilya Funtov Points 1

Si je comprends bien, notify_one appelle pthread_cond_signal. Si c'est le cas, qu'en pensez-vous ?

Pour un comportement d'ordonnancement prévisible et pour éviter les réveils perdus, le mutex doit être maintenu lors de la signalisation d'une variable de condition.

https://www.unix.com/man-page/hpux/3T/pthread_cond_signal/

Tous les threads qui attendent la variable de condition sont suspendus jusqu'à ce qu'un autre thread utilise la fonction de signal :

pthread_cond_signal(&myConVar) ;

Dans ce cas, le mutex doit être verrouillé avant l'appel de la fonction et déverrouillé après.

https://www.i-programmer.info/programming/cc/12288-fundamental-c-condition-variables.html

J'ai personnellement eu des cas où des notifications ont été manquées parce que notify_one a été appelé sans verrouiller le mutex.

0voto

Fan Jing Points 9

Dans certains cas, lorsque le cv peut être occupé(verrouillé) par d'autres threads. Vous devez obtenir le verrou et le libérer avant notify_*().
Sinon, le notify_*() peut ne pas être exécuté du tout.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X