• C++条件变量


    一、有什么用:

    当需要死循环判断某个条件成立与否时【true or false】,我们往往需要开一个线程死循环来判断,这样非常消耗CPU。使用条件变量,可以让当前线程wait,释放CPU,如果条件改变时,我们再notify退出线程,再次进行判断。

    二、其他解释

    想要修改共享变量(即“条件”)的线程必须:
    1. 获得一个std::mutex
    2. 当持有锁的时候,执行修改动作
    3. 对std::condition_variable执行notify_one或notify_all(当做notify动作时,不必持有锁)

    即使共享变量是原子性的,它也必须在mutex的保护下被修改,这是为了能够将改动正确发布到正在等待的线程。

    任意要等待std::condition_variable的线程必须:
    1. 获取std::unique_lock<std::mutex>,这个mutex正是用来保护共享变量(即“条件”)的
    2. 执行wait, wait_for或者wait_until. 这些等待动作原子性地释放mutex,并使得线程的执行暂停
    3. 当获得条件变量的通知,或者超时,或者一个虚假的唤醒,那么线程就会被唤醒,并且获得mutex. 然后线程应该检查条件是否成立,如果是虚假唤醒,就继续等待。

    【注: 所谓虚假唤醒,就是因为某种未知的罕见的原因,线程被从等待状态唤醒了,但其实共享变量(即条件)并未变为true。因此此时应继续等待】

     https://en.cppreference.com/w/cpp/thread/condition_variable

    三、代码

    std::deque<int> q;
    std::mutex mu;
    std::condition_variable cond;
    
    void function_1() //生产者
    {
        int count = 10;
        while (count > 0) 
        {
            std::unique_lock<std::mutex> locker(mu);
            q.push_front(count);
            locker.unlock();
            cond.notify_one();  // Notify one waiting thread, if there is one.
            std::this_thread::sleep_for(std::chrono::seconds(1));
            count--;
        }
    }
    
    void function_2() //消费者
    {
        int data = 0;
        while (data != 1) 
        {
            std::unique_lock<std::mutex> locker(mu);
            while (q.empty())
                cond.wait(locker); // Unlock mu and wait to be notified
            data = q.back();
            q.pop_back();
            locker.unlock();
            std::cout << "t2 got a value from t1: " << data << std::endl;
        }
    }
    int main() 
    {
        std::thread t1(function_1);
        std::thread t2(function_2);
        t1.join();
        t2.join();
        return 0;
    }

    核心:

    ①、在消费者里判断队列是否为空后,如果不为空则wait,等待生产者发送notify信号

    ②、在生产者那里,如果生产了任务,则发送notify信号,告诉消费者可以试图退出wait,判断队列是否为空,如果有任务则调度处理任务,如果还是空则说明此次notify是错误的,可能是其他地方发出来干扰的,生产者继续wait。

    ③、流程:

    软件开启,生成消费者线程消费队列,应该是一个while循环,在循环里获取锁,再来一个while循环判断条件,如果条件不成立则wait,wait会自动释放锁;

    此时消费者已经没有锁了,在生产者线程里,获取锁,然后往里面加任务,退出作用域释放锁,然后notify告知消费者退出wait,消费者重新获取锁,然后从队列里取任务;

    整个过程,生产者加任务时生产者持有锁,消费者取任务时消费者持有锁。

    对于此处补充:https://www.cnblogs.com/judes/p/11132918.html

  • 相关阅读:
    maven 配置国内镜像仓库加速获取jar包的配置方法
    java 开发工具包 jdk 64位 jdk-8u221-windows-x64.exe 迅雷下载
    idea 更新后和新的直接安装前,都需要配置 idea64.exe.vmoptions 后再使用
    OpenCV编程入门目录
    类 — 成员函数的重载、覆盖与隐藏
    STL不同容器的使用方法
    STL容器之间的差异和联系
    STL之顺序容器 deque 动态数组
    Win10下Anaconda3安装CPU版本TensorFlow并使用Pycharm开发
    CNN中已知input_size、kernel_size、padding、stide计算output公式的理解
  • 原文地址:https://www.cnblogs.com/judes/p/11230628.html
Copyright © 2020-2023  润新知