当前位置: 首页 > news >正文

【C++】条件变量condition_variable(1)

互斥量(mutex)和条件变量(condition_variable)在多线程编程中通常是配合使用的,它们解决的是不同层面的问题。简单来说:

  1. 互斥量(mutex 用于 互斥访问 共享资源,保证同一时间只有一个线程可以访问临界区,防止数据竞争。

  2. 条件变量(condition_variable 解决的是 线程同步 的问题,允许线程在特定条件满足前进入等待状态,并在条件满足时被通知唤醒。

为啥有了互斥量还需要 condition_variable

互斥量本身只能防止多个线程同时访问共享资源,但不能用于线程间的等待和通知机制。如果线程需要等待某个条件成立才能继续执行,仅靠互斥量会导致忙等待(不断轮询检查条件),这样会浪费 CPU 资源。而 condition_variable 可以让线程高效等待,避免资源浪费。

具体场景:

1. 没有 condition_variable 的情况(忙等待)
std::mutex mtx;
bool ready = false; // 共享资源的状态

void worker() {
    while (true) {
        mtx.lock();
        if (ready) {
            std::cout << "Processing data..." << std::endl;
            mtx.unlock();
            break;
        }
        mtx.unlock();
        std::this_thread::sleep_for(std::chrono::milliseconds(100)); // 轮询等待
    }
}

这里,worker 线程必须不断轮询 ready 变量是否变为 true,即使 ready 很长时间都不变,线程仍然会定期尝试获取互斥锁,导致 CPU 资源浪费。

2. 使用 condition_variable(高效等待)
std::mutex mtx;
std::condition_variable cv;
bool ready = false;

void worker() {
    std::unique_lock<std::mutex> lock(mtx);
    cv.wait(lock, [] { return ready; }); // 线程会在这里等待,直到 ready 变为 true
    std::cout << "Processing data..." << std::endl;
}

void producer() {
    std::this_thread::sleep_for(std::chrono::seconds(2)); // 模拟数据准备时间
    std::lock_guard<std::mutex> lock(mtx);
    ready = true;
    cv.notify_one(); // 唤醒等待的线程
}

在这个版本中,worker 线程会在 cv.wait()阻塞,直到 producer 线程调用 cv.notify_one(),线程才会被唤醒并继续执行。这种方式避免了 CPU 资源的浪费,提升了效率。

总结:

  • 互斥量 只负责保护数据的访问,不能用来通知其他线程状态的变化。
  • condition_variable 让线程可以高效等待某个条件,避免忙等待带来的性能浪费。
  • 它们通常配合使用,condition_variable 依赖 mutex 来保护共享数据的状态。

因此,即使有了互斥量,在需要线程同步的场景下,我们仍然需要 condition_variable 来高效地协调线程的执行顺序。

想象一个餐厅点餐的场景,我们用它来类比 mutexcondition_variable 的作用。


场景描述

在一个餐厅里:

  • 顾客点餐后需要等待厨师做好饭。
  • 厨师在顾客点餐之前是不会做饭的。
  • 顾客不能频繁去后厨查看饭是不是好了,否则会很麻烦。
  • 当饭做好后,厨师会通知顾客来取饭。

不用 condition_variable,仅用 mutex(忙等待的情况)

如果没有 condition_variable,顾客会不断去后厨查看饭是否好了:

std::mutex mtx;
bool food_ready = false; // 饭是否做好

void customer() {
    while (true) { 
        mtx.lock();
        if (food_ready) {
            std::cout << "顾客:拿到饭,开始吃!" << std::endl;
            mtx.unlock();
            break;
        }
        mtx.unlock();
        std::this_thread::sleep_for(std::chrono::milliseconds(100)); // 轮询等待
        std::cout << "顾客:饭好了没?" << std::endl;
    }
}

void chef() {
    std::this_thread::sleep_for(std::chrono::seconds(3)); // 模拟做饭时间
    mtx.lock();
    food_ready = true;
    std::cout << "厨师:饭做好了!" << std::endl;
    mtx.unlock();
}

问题:

  • 顾客不停地轮询后厨(忙等待),就像线程不断检查共享变量 food_ready,浪费 CPU 资源。
  • 这个过程即使饭还没好,顾客仍然会每隔一段时间就去“打扰”后厨(检查 food_ready 变量)。

使用 condition_variable(高效等待)

如果用 condition_variable,顾客可以安心等厨师通知,而不是不停地去检查。

std::mutex mtx;
std::condition_variable cv;
bool food_ready = false;

void customer() {
    std::unique_lock<std::mutex> lock(mtx);
    cv.wait(lock, [] { return food_ready; }); // 等待厨师通知
    std::cout << "顾客:拿到饭,开始吃!" << std::endl;
}

void chef() {
    std::this_thread::sleep_for(std::chrono::seconds(3)); // 模拟做饭时间
    std::lock_guard<std::mutex> lock(mtx);
    food_ready = true;
    std::cout << "厨师:饭做好了!" << std::endl;
    cv.notify_one(); // 通知顾客饭已经好了
}

改进点:

  • 顾客不用一直去问饭好了没,而是安心等待,一旦厨师通知,顾客才去取饭。
  • 这个机制避免了不必要的 CPU 轮询,就像 cv.wait() 让线程休眠,直到 cv.notify_one() 叫醒它。

总结

方式现实类比编程效果
只用 mutex顾客不停地去厨房问“饭好了没?”线程不断检查变量(忙等待,浪费 CPU)
condition_variable + mutex顾客坐着等,厨师做好饭后叫他来取线程高效等待,不浪费资源

所以,互斥量(mutex)解决数据竞争问题,而 condition_variable 解决高效等待和线程同步的问题,它们是互补的

相关文章:

  • P6412题解
  • 海量数据融合互通丨TiDB 在安徽省住房公积金监管服务平台的应用实践
  • 【项目】负载均衡式在线OJ
  • 强化学习和最优控制 - 知识图谱
  • 04.基于C++实现多线程TCP服务器与客户端通信
  • 数据结构(树)
  • 用套接字在网络中传送对象的时候为什么需要序列化?
  • ROS分布式部署通信
  • 【NLP 32、文本匹配任务 —— 深度学习】
  • 电子扫盲课(郑州大学北校区计协讲座第一讲)
  • 求最大公约数【C/C++】
  • LINUX网络基础 [五] - HTTP协议
  • 中级网络工程师面试题参考示例(3)
  • 使用 MyBatis XML 和 QueryWrapper 实现动态查询
  • 大模型信息整理
  • JDBC事务管理与DAO模式实践
  • 加餐 —— Spring Boot 项目转 Solon 项目工具
  • 电子学会—2024年月6青少年软件编程(图形化)四级等级考试真题——魔法门
  • 【玩转MySQL数据字典】MySQL数据字典与常用操作指令
  • visual studio中解决方案和项目的关系?如何在同一个解决方案中添加项目?
  • 网站建设_网站设计 app制作/全媒体运营师报考条件
  • 网站动态图怎么做/宁波seo在线优化方案
  • 网站建设副业/优化网站的软件下载
  • 大型电商网站建设/上海关键词优化排名软件
  • 网站建设软件开发工作室整站模板/百度网盘人工客服电话
  • wordpress做论坛网站/如何网站seo