C++中std::condition_variable_any、std::lock_guard 和 std::unique_

1、背景

在 C++ 多线程编程中,同步 和 互斥 是至关重要的概念。C++ 标准库提供了多种同步机制,其中 std::condition_variable_any、std::lock_guard 和 std::unique_lock 是经常被用到的工具。本文将详细介绍这三者的用途、区别、适用场景,并通过示例展示如何正确使用它们。

2、std::lock_guard

std::lock_guard 是 C++ 提供的一个 RAII(资源获取即初始化)风格的互斥锁管理器,用于在作用域内 自动管理 std::mutex 的加锁和解锁,确保不会发生死锁或者忘记解锁的问题,它是一种轻量级自动管理锁。

#include <iostream>
#include <thread>
#include <mutex>

std::mutex mtx;

void print_message(const std::string& msg) {
    std::lock_guard<std::mutex> lock(mtx); // 自动加锁,作用域结束时自动解锁
    std::cout << msg << std::endl;
}

int main() {
    std::thread t1(print_message, "Hello from thread 1");
    std::thread t2(print_message, "Hello from thread 2");

    t1.join();
    t2.join();

    return 0;
}

该锁主要适用于短生命周期的互斥操作。

3、std::unique_lock

与std::lock_guard相比,std::unique_lock支持更加灵活的互斥锁管理。主要有以下几个功能:

  • 支持 defer_lock(延迟加锁),允许在稍后手动调用 lock();
  • 支持手动 unlock(),适用于更复杂的同步场景。
#include <iostream>
#include <thread>
#include <mutex>

std::mutex mtx;

void worker() {
    std::unique_lock<std::mutex> lock(mtx, std::defer_lock); // 不自动加锁
    std::cout << "Before locking...\n";

    lock.lock(); // 需要时手动加锁
    std::cout << "Worker thread acquired lock\n";

    lock.unlock(); // 需要时手动解锁
    std::cout << "Worker thread released lock\n";
}

int main() {
    std::thread t(worker);
    t.join();
    return 0;
}

  • 支持 try_lock,尝试加锁但不阻塞;
#include <iostream>
#include <thread>
#include <mutex>
#include <chrono>

std::mutex mtx;

void worker() {
    std::unique_lock<std::mutex> lock(mtx, std::try_to_lock); // 尝试加锁

    if (lock.owns_lock()) { // 判断是否成功加锁
        std::cout << "Worker acquired lock\n";
    } else {
        std::cout << "Worker failed to acquire lock\n";
    }
}

int main() {
    std::unique_lock<std::mutex> main_lock(mtx); // 先加锁,让 worker 线程无法获取锁

    std::thread t(worker);
    std::this_thread::sleep_for(std::chrono::milliseconds(50)); // 模拟主线程持锁一段时间

    main_lock.unlock(); // 释放锁

    t.join();
    return 0;
}

  • 支持 timed_lock,尝试在一定时间内加锁;
#include <iostream>
#include <thread>
#include <mutex>
#include <chrono>

std::mutex mtx;

void worker() {
    std::unique_lock<std::mutex> lock(mtx, std::defer_lock); // 延迟加锁

    if (lock.try_lock_for(std::chrono::seconds(2))) { // 等待最多2秒尝试加锁
        std::cout << "Worker acquired lock\n";
    } else {
        std::cout << "Worker failed to acquire lock within timeout\n";
    }
}

int main() {
    std::unique_lock<std::mutex> main_lock(mtx); // 先加锁

    std::thread t(worker);

    std::this_thread::sleep_for(std::chrono::seconds(3)); // 持锁超过 worker 的等待时间
    main_lock.unlock(); // 释放锁

    t.join();
    return 0;
}

4、std::condition_variable_any

std::condition_variable 只能和 std::unique_lockstd::mutex 结合使用,但是 std::condition_variable_any 可以适配 std::shared_mutex,从而实现 读写者模型。

#include <iostream>
#include <thread>
#include <shared_mutex>
#include <condition_variable>

std::shared_mutex rw_mutex;
std::condition_variable_any cv;
bool data_ready = false;
int data = 0;

// 读线程(多个线程可以共享读取)
void reader(int id) {
    std::shared_lock<std::shared_mutex> lock(rw_mutex);
    cv.wait(lock, [] { return data_ready; }); // 等待数据就绪
    std::cout << "Reader " << id << " read data: " << data << std::endl;
}

// 写线程(独占写入)
void writer() {
    std::this_thread::sleep_for(std::chrono::seconds(2));
    
    {
        std::unique_lock<std::shared_mutex> lock(rw_mutex);
        data = 42;
        data_ready = true;
    }

    cv.notify_all(); // 唤醒所有等待的读线程
}

int main() {
    std::thread readers[3] = {
        std::thread(reader, 1),
        std::thread(reader, 2),
        std::thread(reader, 3)
    };

    std::thread writer_thread(writer);

    for (auto& r : readers) r.join();
    writer_thread.join();

    return 0;
}
  • std::condition_variable_any 与 std::condition_variable 的区别
特性std::condition_variablestd::condition_variable_any
兼容锁类型只能配合std::unique_lock<std::mutx>兼容所有符合Lockable规范的锁如std::unique_lock<std::shared_mutex>
适用范围只能用于std::mutex适用于std::mutex、std::shared_mutex等
适用场景经典生产者-消费者模型适用于读写锁等更多场景
线程等待允许多个线程等待同一条件允许多个线程等待同一条件

5、结论

  • 如果你只需要在作用域内加锁并确保自动释放,使用 std::lock_guard。
  • 如果你需要更灵活的锁管理,如手动解锁或尝试加锁,使用 std::unique_lock。
  • 如果你需要线程间的条件同步,使用 std::condition_variable_any或者std::condition_variable,再根据std::mutex和std::shared_mutex哪个可以满足需求决定使用那一个条件变量,std::condition_variable_any比std::condition_variable功能更加强大,因此它的性能开销应该比std::condition_variable更大,因此如果std::condition_variable可以满足需要,最好使用std::condition_variable,否则使用std::condition_variable_any。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/971999.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【AI面板识别】

题目描述 AI识别到面板上有N&#xff08;1 ≤ N ≤ 100&#xff09;个指示灯&#xff0c;灯大小一样&#xff0c;任意两个之间无重叠。 由于AI识别误差&#xff0c;每次别到的指示灯位置可能有差异&#xff0c;以4个坐标值描述AI识别的指示灯的大小和位置(左上角x1,y1&#x…

朴素模式匹配算法与KMP算法(有next[]和nextval[]详细讲解

这篇文章是建立在上篇文章的基础上的,看此篇文章要有串的基本知识 举个例子引进我们今天的知识 假设我们这里有两个字符串,一个主串,一个子串 主串: aaa223aa225 子串: aa22 我们这里需要进行匹配,传统的朴素模式匹配算法,就是主串下标i从1开始,主串j从1开始…

文件操作(PHP)(小迪网络安全笔记~

免责声明&#xff1a;本文章仅用于交流学习&#xff0c;因文章内容而产生的任何违法&未授权行为&#xff0c;与文章作者无关&#xff01;&#xff01;&#xff01; 附&#xff1a;完整笔记目录~ ps&#xff1a;本人小白&#xff0c;笔记均在个人理解基础上整理&#xff0c;…

【分治法】棋盘覆盖问题 C/C++(附代码和测试实例及算法分析)

问题描述 在一个 2 k 2 k 2^k \times 2^k 2k2k大小的棋盘中&#xff0c;有一个与其他方块不同的特殊方块&#xff0c;如下图红色方块。另有4种形态不同的L型骨块&#xff08;见下图&#xff09;&#xff0c;要用图示四种骨块覆盖棋盘上除特殊方格外的其他所有方格&#xff0c…

el-table的hasChildren不生效?子级没数据还显示箭头号?树形数据无法展开和收缩

问题&#xff1a;明明子级只有一条数据&#xff0c;还显示箭头号 原因&#xff1a;最开始row-key写的是id,父级和子级都有该属性&#xff0c;所以展开失效了。 解决方法&#xff1a;row-key&#xff1a;id改成 row-key"name"

2002-2019年各省人口老龄化程度数据

2002-2019年各省人口老龄化程度数据 1、时间&#xff1a;2002-2019年 2、来源&#xff1a;国家统计局、统计年鉴 3、指标&#xff1a;地区、年度、六十五岁以上占比 4、范围&#xff1a;31省 5、指标解释&#xff1a;人口老龄化是指人口生育率降低和人均寿命延长导致的总人…

面向机器学习的Java库与平台简介、适用场景、官方网站、社区网址

Java机器学习的库与平台 最近听到有的人说要做机器学习就一定要学Python&#xff0c;我想他们掌握的知道还不够系统全面。本文作者给大家介绍几种常用Java实现的机器学习库&#xff0c;快快收藏加关注吧&#xff5e; Java机器学习库表格 Java机器学习库整理库/平台概念适合场…

MySQL 之服务器配置和状态(MySQL Server Configuration and Status)

MySQL 之服务器配置和状态 1 MySQL 架构和性能优化 1.3 服务器配置和状态 设置 MySQL 服务的特性&#xff0c;可以通过 mysqld 服务选项&#xff0c;服务器系统变量和服务器状态变量这三个方面来进行设置和查看。 官方文档 https://dev.mysql.com/doc/refman/8.0/en/serve…

Linux的基础指令和环境部署,项目部署实战(下)

目录 上一篇&#xff1a;Linxu的基础指令和环境部署&#xff0c;项目部署实战&#xff08;上&#xff09;-CSDN博客 1. 搭建Java部署环境 1.1 apt apt常用命令 列出所有的软件包 更新软件包数据库 安装软件包 移除软件包 1.2 JDK 1.2.1. 更新 1.2.2. 安装openjdk&am…

LabVIEW无刷电机控制器检测系统

开发了一种基于LabVIEW的无刷电机控制器检测系统。由于无刷电机具有高效率、低能耗等优点&#xff0c;在电动领域有取代传统电机的趋势&#xff0c;而无刷电机的核心部件无刷电机控制器产量也在不断增长。然而&#xff0c;无刷电机控制器的出厂检测仍处于半自动化状态&#xff…

《仙台有树》里的馅料(序)

《仙台有树》一起追剧吧&#xff08;二&#xff09;&#xff1a;馅料合集概览 ●德爱武美玩&#xff0c;全面发展 ●猜猜我是谁&真假美清歌 ●失忆的风还是吹到了仙台 ●霸道师徒强制收&你拜我&#xff0c;我拜你&#xff0c;师徒徒师甜蜜蜜 ●霸道总裁强制爱 ●仙台有…

网站搭建基本流程

需求分析&#xff1a; 实现网站搭建的过程&#xff1a;首先进行网站的需求性分析 网站可分为前台系统和后台系统&#xff0c;由不同的功能拆分为不同的模块 如下是一个电商网站可以拆分出的模块&#xff1a; 在编写代码前&#xff0c;我们要先对网站进行架构&#xff0c;通过…

反射机制的简单示例

一个使用反射机制的简单示例&#xff0c;这个示例将展示如何使用反射来实现一个通用的数据导出功能。 首先&#xff0c;让我们创建必要的项目结构和文件&#xff1a; 首先修改 pom.xml 添加依赖&#xff1a; <?xml version"1.0" encoding"UTF-8"?&…

Qt:多元素控件

目录 多元素控件介绍 QListWidget QTableWidget QTreeWidget 多元素控件介绍 多元素控件表示这个控件中包含了很多的元素&#xff0c;元素可能指的是字符串&#xff0c;也可以指的是更加复杂的数据结构、图片等等 Qt 中提供的多元素控件有: QListWidgetQListViewQTableW…

DeepSeek 助力 Vue 开发:打造丝滑的范围选择器(Range Picker)

前言&#xff1a;哈喽&#xff0c;大家好&#xff0c;今天给大家分享一篇文章&#xff01;并提供具体代码帮助大家深入理解&#xff0c;彻底掌握&#xff01;创作不易&#xff0c;如果能帮助到大家或者给大家一些灵感和启发&#xff0c;欢迎收藏关注哦 &#x1f495; 目录 Deep…

STL —— 洛谷字符串(string库)入门题(蓝桥杯题目训练)(一)

目录 一、B2109 统计数字字符个数 - 洛谷 算法代码&#xff1a; 1. 引入库和命名空间 2. 主函数 3. 读取输入 4. 变量初始化 5. 遍历字符串 6. 输出结果 7. 返回值 总结 评测记录&#xff1a; 二、B2110 找第一个只出现一次的字符 - 洛谷 方法一&#xff1a;算法代…

Golang GORM系列:GORM并发与连接池

GORM 是一个流行的 Go 语言 ORM&#xff08;对象关系映射&#xff09;库&#xff0c;用于简化数据库操作。它支持连接池和并发访问功能&#xff0c;这些功能对于高性能、高并发的应用场景非常重要。本文结合示例详细介绍gorm的并发处理能力&#xff0c;以及如何是哟个连接池提升…

C#之上位机开发---------C#通信库及WPF的简单实践

〇、上位机&#xff0c;分层架构 界面层 要实现的功能&#xff1a; 展示数据 获取数据 发送数据 数据层 要实现的功能&#xff1a; 转换数据 打包数据 存取数据 通信层 要实现的功能&#xff1a; 打开连接 关闭连接 读取数据 写入数据 实体类 作用&#xff1a; 封装数据…

Ubuntu24安装MongoDB(解压版)

目录 0.需求说明1.环境检查2.下载软件2.1.下载MongoDB服务端2.2.下载MongoDB连接工具(可略过)2.3.检查上传或下载的安装包 3.安装MongoDB3.1.编辑系统服务3.2.启动服务3.3.客户端连接验证3.3.1.创建管理员用户 4.远程访问4.1.开启远程访问4.2.开放防火墙 0.需求说明 问&#x…

《DeepSeek-V3:人工智能大语言模型》

《DeepSeek-V3:人工智能大语言模型》 1. 引言 我们介绍了 DeepSeek-V3,这是一个强大的专家混合 (MoE) 语言模型,总共有 671B 个参数,每个令牌激活了 37B。 为了实现高效的推理和具有成本效益的训练,DeepSeek-V3 采用了多头潜在注意力 (MLA) 和 DeepSeekMoE 架构,这些…