mardi 16 juin 2020

How to decrese the possibility of the producer acquiring the lock whereas the consumer could not get the lock when using std::condition_variable?

How can I decrease the possibility of the producer(i.e. main thread in the code snippet code below) acquiring the lock whereas the consumer(i.e. wait thread) could not get the lock? It is would be better if you could tell me a method to avoid it. I don't think it is a good idea to use std::thread::sleep_for or std::thread::yield. And I have done some test and found that there is no effect when using std::thread::yield.

I have thought about it for a long time, I would be grateful to have some help with this question.

If you run the code snippet, you may see such output:

Waiting... 
test 
Notifying falsely... 
Notifying true change... 
Notifying true change... 
Notifying true change... 
Notifying true change... 
Notifying true change... 
Notifying true change...
(**many many such output**)
Notifying true change... 
test 
...finished waiting. i == 1

Here is the related code snippet(check https://godbolt.org/z/9dwDJN):

#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, []{std::cout<<"test"<<std::endl; 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 falsely...\n";
    cv.notify_one(); // waiting thread is notified with i == 0. 
    // cv.wait wakes up, checks i, and goes back to waiting 

    std::unique_lock<std::mutex> lk(cv_m);
    i = 1;
    while (!done)
    {
        std::cout << "Notifying true change...\n";
        lk.unlock();
        cv.notify_one(); // waiting thread is notified with i == 1, cv.wait returns 
        //std::this_thread::sleep_for(std::chrono::seconds(1));   // I don't think it is good method.
        //std::this_thread::yield();  //Maybe, this does not work.
        lk.lock();
    }
}

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

Aucun commentaire:

Enregistrer un commentaire