c ++ 11 multithreaded record 6: Condition variables (condition variables)

https://www.youtube.com/watch?v=13dFggo4t_I video address

Example 1

Consider a scenario: there is one global queue deque, the thread A push data (write), thread B data extracted (read) from the deque to the deque.
Deque object is to do this resource access control with the mutex, code is as follows:

std::deque<int> q;
std::mutex mu;

void func1() {
    int ct = 10;
    while (ct > 0) {
        std::unique_lock<std::mutex> lock(mu);
        q.push_front(ct);
        lock.unlock();
        std::this_thread::sleep_for(chrono::seconds(1));
        ct --;
    }
}

void func2() {
    int data = 0;
    while (data != 1 ) {
        std::unique_lock<std::mutex> lock(mu);
        if (!q.empty()) {
            data = q.back();
            q.pop_back();
            lock.unlock();
            ...
        } else {
            lock.unlock();
        }
    }
}

int main() {
    std::thread t1(func1);
    std::thread t2(func2);
    t1.join();
    t2.join();
    return 0; 
}

T1 thread, the cycle is pushed to the queue of data, each sleep one second;. As a "producer"
thread t2, the continuously read data from the queue (first determines whether there is data); as a "consumer . "

There is a problem: Thread t2, the judge will first deque is empty; if empty, will perform the unlock, and then immediately enter the next cycle, resulting in busy waiting (repeated frequently to determine whether a state is true).

One solution is as follows:

void func2() {
    ...
    } else {
        lock.unlock();
        std::this_thread::sleep_for(chrono::seconds(1));
    }
}

A period of time sleeping in the discovery queue is empty, you can solve the problem to some extent.
But the time variable is set to determine what the value is not good; the set is too small, could return to busy waiting; set too large, it will not lead to timely access to data

Condition variable

It can be a good deal with this problem with variable conditions, so that consumers do not "blindly wait"

std::deque<int> q;
std::mutex mu;
std::condition_variable cond;

void func1() {
    int ct = 10;
    while (ct > 0) {
        std::unique_lock<std::mutex> lock(mu);
        q.push_front(ct);
        lock.unlock();
        cond.notify_one(); // wake up one waiting thread
        // cond.notify_all(); // wake up all waiting threads
        std::this_thread::sleep_for(chrono::seconds(1));
        ct --;
    }
}

void func2() {
    int data = 0;
    while (data != 1 ) {
        std::unique_lock<std::mutex> lock(mu);
        cond.wait(lock, [](){ return !q.empty(); });
        data = q.back();
        q.pop_back();
        lock.unlock();
    }
}

Producer thread, after the data is pushed into the deque execution notify_one (), you can wake up one thread; similar to a bank counter called.
Consumers thread, just cond.wait (lock, ...), waiting for sleep until they were "called number"; sleep waiting, do not take up cpu time (when it is awakened, the second parameter will continue to sleep if it returns false, is true will execute down)
Note that cond.wait (lock) into the will first release the lock before the occupation of sleep; will first take up mutex when it is awakened.

summary

condition_variable Roughly speaking, it may be similar to a "wake-up service."

Guess you like

Origin www.cnblogs.com/ChenLambda/p/11832656.html