码迷,mamicode.com
首页 > 编程语言 > 详细

c++11多线程记录6:条件变量(condition variables)

时间:2019-11-11 09:38:34      阅读:91      评论:0      收藏:0      [点我收藏+]

标签:sleep   lse   code   地址   cpp   消费者   else   解决问题   main   

https://www.youtube.com/watch?v=13dFggo4t_I视频地址

实例1

考虑这样一个场景:存在一个全局队列deque,线程A向deque中推入数据(写),线程B从deque中取出数据(读).
deque这个资源对象就需要用mutex做访问控制,代码如下:

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中,循环向队列中推入数据,每次睡眠1秒;做为“生产者”.
线程t2中,不断地从队列中读出数据(先判断是否有数据);做为“消费者”.

存在一个问题:线程t2中,会先判断deque是否为空;如果为空,会执行unlock,然后马上进入下一次循环,造成busy waiting(反复频繁地判断某一状态是否为true).

一种解决方法如下:

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

在发现队列为空时睡眠一段时间time,可以一定程度上解决问题。
但是变量time设置成什么数值并不好确定;设置的过小,可能会回到busy waiting;设置的过大,会导致不能及时的获取数据

Condition variable

用条件变量可以很好的处理这个问题,让消费者不用“盲目等待”

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();
    }
}

生产者线程中,数据被推入deque后执行notify_one(),就可以唤醒某一个线程;类似于银行柜台叫号.
消费者线程中,只需要cond.wait(lock,...),睡眠等待,直到被“叫号”;睡眠等待过程中不占用cpu时间.(被唤醒时,第二个参数如果返回false会继续睡眠,为true则会往下执行)
注意这里cond.wait(lock)进入睡眠之前会先释放对lock的占用;被唤醒时会先占用mutex.

小结

condition_variable粗略的说,可能类似一个“唤醒服务”.

c++11多线程记录6:条件变量(condition variables)

标签:sleep   lse   code   地址   cpp   消费者   else   解决问题   main   

原文地址:https://www.cnblogs.com/ChenLambda/p/11832656.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!