c++,mutex,unique_lock,recursive_mutex,shared_mutex对比分析

当处理多线程并发时,正确使用锁是确保线程安全的关键。

1. std::mutex(互斥锁):

std::mutex 是C++标准库提供的最基本的锁。它的基本使用如下:

#include <iostream>
#include <mutex>
#include <thread>std::mutex myMutex;void sharedResourceAccess() {std::lock_guard<std::mutex> lock(myMutex);// 访问共享资源的代码std::cout << "Accessing shared resource...\n";
}int main() {std::thread t1(sharedResourceAccess);std::thread t2(sharedResourceAccess);t1.join();t2.join();return 0;
}

注意事项:

  • 使用 std::lock_guard 是一种简单而安全的方式,它会在作用域结束时自动释放锁。
  • 避免手动调用 unlock(),因为忘记释放锁可能导致严重的问题。

2. std::unique_lock:

std::unique_lock 提供了更灵活的锁定和解锁方式,同时支持条件变量。在某些情况下,这种灵活性是很有用的:

#include <iostream>
#include <mutex>
#include <thread>std::mutex myMutex;void sharedResourceAccess() {std::unique_lock<std::mutex> lock(myMutex);// 访问共享资源的代码std::cout << "Accessing shared resource...\n";// lock.unlock();  // 可以手动解锁
}int main() {std::thread t1(sharedResourceAccess);std::thread t2(sharedResourceAccess);t1.join();t2.join();return 0;
}

注意事项:

  • std::unique_lock 可以在构造时不锁定,也可以手动解锁。
  • 支持条件变量,可以灵活地等待某个条件成立后再继续执行。

3. std::recursive_mutex:

std::recursive_mutex 允许同一个线程多次锁定同一把锁。这对于递归函数可能需要在同一线程中多次获取锁的情况很有用:

#include <iostream>
#include <mutex>
#include <thread>std::recursive_mutex myRecursiveMutex;void recursiveAccess(int depth) {std::unique_lock<std::recursive_mutex> lock(myRecursiveMutex);if (depth > 0) {recursiveAccess(depth - 1);}// 访问共享资源的代码std::cout << "Accessing shared resource at depth " << depth << "...\n";
}int main() {std::thread t1(recursiveAccess, 3);t1.join();return 0;
}

注意事项:

  • 递归锁允许同一线程多次获取锁,但要小心不要导致死锁。

4. std::shared_mutex:

std::shared_mutex 是C++14标准引入的互斥锁,它提供了共享/独占两种锁定方式。这使得多个线程可以同时共享资源,而只有一个线程可以独占地修改资源。这在某些情况下能够提高并发性能。

以下是 std::shared_mutex 的主要特点和用法:

  1. 共享锁(Shared Lock):

    • 多个线程可以同时获得共享锁,这允许它们并发地读取共享资源。
    • 共享锁使用 std::shared_lock 来获取。
    #include <shared_mutex>std::shared_mutex mySharedMutex;void readOperation() {std::shared_lock<std::shared_mutex> lock(mySharedMutex);// 读取共享资源的代码
    }
    
  2. 独占锁(Exclusive Lock):

    • 只有一个线程可以获得独占锁,这使得它能够独占地修改共享资源。
    • 独占锁使用 std::unique_lock 来获取。
    #include <shared_mutex>std::shared_mutex mySharedMutex;void writeOperation() {std::unique_lock<std::shared_mutex> lock(mySharedMutex);// 修改共享资源的代码
    }
    
  3. 避免写者饥饿(Writer Starvation Avoidance):

    • std::shared_mutex 的设计旨在避免写者饥饿问题,即允许读者和写者以公平的方式争夺锁。
  4. 适用于读多写少的场景:

    • std::shared_mutex 在读多写少的情况下表现得较为优越,因为多个线程可以同时获得共享锁,提高了并发性能。
  5. 注意事项:

    • 使用 std::shared_lock 进行读取操作,使用 std::unique_lock 进行写入操作。
    • 避免在写入操作中使用共享锁,以免破坏写者的互斥性。
#include <iostream>
#include <shared_mutex>
#include <vector>
#include <thread>int sharedData=0;
std::shared_mutex mySharedMutex;void readOperation(int id) {//std::shared_lock<std::shared_mutex> lock(mySharedMutex);mySharedMutex.lock_shared();//手动控制// 读取共享资源的代码std::cout << "Reader " << id << " reading data: " << sharedData << std::endl;mySharedMutex.unlock_shared();//手动控制
}void writeOperation(int id) {//std::unique_lock<std::shared_mutex> lock(mySharedMutex);mySharedMutex.lock();//手动控制// 修改共享资源的代码sharedData=id;std::cout << "Writer " << id << " writing data." << std::endl;mySharedMutex.unlock();//手动控制
}int main() {std::vector<std::thread> readers;std::vector<std::thread> writers;for (int i = 0; i < 5; ++i) {readers.emplace_back(readOperation, i);writers.emplace_back(writeOperation, i);}for (auto& reader : readers) {reader.join();}for (auto& writer : writers) {writer.join();}return 0;
}

在这个示例中,读者和写者线程通过 std::shared_mutex 来协调对 sharedData 的读写操作。读者线程使用 std::shared_lock 获得共享锁,而写者线程使用 std::unique_lock 获得独占锁。这样,多个读者可以同时读取,而写者会独占地修改共享资源。

以下是对 std::mutexstd::unique_lockstd::recursive_mutex,和 std::shared_mutex 的特点进行比较的表格:

特点std::mutexstd::unique_lockstd::recursive_mutexstd::shared_mutex
类型互斥锁可锁定、可解锁的锁递归互斥锁共享/独占互斥锁
RAII 风格有(使用 std::lock_guard有(std::unique_lock
支持条件变量不支持支持不支持支持
是否支持递归不支持不支持支持不支持
多线程性能适用于大多数场景,较轻量级较为灵活,适用于复杂的场景适用于需要递归锁的场景适用于读多写少的场景
锁定粒度整个作用域内的代码可以在较小的范围内进行锁定和解锁整个作用域内的代码可以同时支持独占和共享访问
死锁风险高(如果未正确解锁,可能导致死锁)低(通过 std::lock() 可以避免死锁)递归锁允许同一线程多次获取锁,小心死锁风险低(支持共享和独占访问,适当使用可以减少死锁风险)
内存开销低(较为轻量级)较高(提供了更多的功能)较高(需要额外的信息来支持递归锁)较高(需要维护更多状态信息)

这个比较表格总结了这些锁的主要特点,但具体的选择取决于你的应用场景和需求。通常来说,std::mutex 是最基本的锁,而 std::unique_lock 提供了更多的灵活性,特别是在需要支持条件变量的情况下。std::recursive_mutex 对于需要在同一线程中多次获取锁的递归情况很有用。std::shared_mutex 则适用于读多写少的场景,提供了更好的并发性能。

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

电池管理系统中算法的多种算法融合介绍

BMS电池管理系统 是一种用于电池组中的单个电池管理的系统&#xff0c;以确保其安全性、寿命和性能。BMS系统通过采集电池信息并对其进行分析&#xff0c;以确保电池组的正常运行。在BMS电池管理系统中&#xff0c;涉及到了许多算法&#xff0c;包括最大功率点追踪算法、SOC计算…

【RK3399 PCIE调试——硬件信息资源获取】

一、1、 硬件接口 二、2、 PCB原理图 三、 官网地址&#xff1a; https://t.rock-chips.com/portal.php 相关资料和固件烧写可参考资料下载菜单

WPF 使用矢量字体图标

矢量字体图标 在WPF项目中经常需要显示图标&#xff0c;但是项目改动后&#xff0c;有时候需要替换和修改图标&#xff0c;这样非常麻烦且消耗开发和美工的时间。为了快速开发项目&#xff0c;节省项目时间&#xff0c;使用图标矢量字体图标是一个非常不错的选择。 矢量字体图标…

基于数学形态学的点云强度均衡滤波

目录 一、相关介绍 二、相关原理 三、实现代码 四、运行结果 一、相关介绍 点云的强度应该是叫做反射率,在软件处理层面主要是靠点云的xyz坐标,以及时间特征来做识别,而如果有了RGB,反射率等辅助信息,识别的效率和精确度会大大提升。 在点云数据无RGB色彩信息的情况下,…

一个人能不能快速搭建一套微服务环境

一、背景 大型软件系统的开发现在往往需要多人的协助&#xff0c;特别是前后端分离的情况下下&#xff0c;分工越来越细&#xff0c;那么一个人是否也能快速搭建一套微服务系统呢&#xff1f; 答案是能的。看我是怎么操作的吧。 二、搭建过程 1、首先需要一套逆向代码生成工…

github 好项目 之 reference

github项目地址 网页网址 点进去以后你可以看到很多关于技术前沿的东西的简单笔记&#xff0c;一些实践的代码&#xff0c;或者是一些快捷键的命令 我个人比较喜欢 latex 的数学公式笔记 以及关于 vim 的一些命令 还有我最喜欢的git命令

算法训练第六十天|84.柱状图中最大的矩形

84.柱状图中最大的矩形&#xff1a; 题目链接 给定 n 个非负整数&#xff0c;用来表示柱状图中各个柱子的高度。每个柱子彼此相邻&#xff0c;且宽度为 1 。 求在该柱状图中&#xff0c;能够勾勒出来的矩形的最大面积。 示例 : 输入&#xff1a;heights [2,1,5,6,2,3] 输出…

虾皮长尾词工具:如何使用关键词工具优化Shopee产品的长尾关键词

在Shopee&#xff08;虾皮&#xff09;平台上&#xff0c;卖家们都希望能够吸引更多的潜在买家&#xff0c;提高产品的曝光率和转化率。而要实现这一目标&#xff0c;了解和使用长尾关键词是非常重要的。本文将介绍长尾关键词的定义、重要性以及如何使用关键词工具来优化Shopee…

手势识别+人脸识别+姿态估计(关键点检测+教程+代码)

手势识别和手势关键点检测是计算机视觉领域中的一个重要研究方向,涉及到从图像或视频中检测人手的位置和姿态信息,并推断出手势的意义。以下是一些可能用到的方法和技术: 手势识别 基于深度学习的手势识别 基于深度学习的手势识别是目前最流行的方法之一。它通常使用卷积神…

二刷Laravel 教程(构建页面)总结Ⅰ

L01 Laravel 教程 - Web 开发实战入门 ( Laravel 9.x ) 一、功能 1.会话控制&#xff08;登录、退出、记住我&#xff09; 2.用户功能&#xff08;注册、用户激活、密码重设、邮件发送、个人中心、用户列表、用户删除&#xff09; 3.静态页面&#xff08;首页、关于、帮助&am…

VMware 安装 macOS虚拟机(附工具包)

VMware 安装 macOS虚拟机&#xff0c;在Windows上体验苹果macOS系统&#xff01; 安装教程&#xff1a;VMware 安装 macOS虚拟机VMware Workstation Pro 是一款强大的虚拟机软件&#xff0c;可让您在 Windows 电脑上运行 macOS 系统。只需简单几步操作&#xff0c;即可轻松安装…

【docker】数据卷和数据卷容器

目录 一、如何管理docker容器中的数据&#xff1f; 二、数据卷 1、数据卷原理 2、数据卷的作用 3、数据卷案例 三、数据卷容器 1、数据卷容器作用 2、数据卷容器案例 四、容器互连&#xff08;centos镜像&#xff09; 一、如何管理docker容器中的数据&#xff1f; 二、…

C语言scanf()函数详解

目录 1. scanf&#xff08;&#xff09;函数简介 1.1 函数原型 1.2 头文件 1.3 返回值 1.4 参数 2.格式说明符 3.输入格式控制 关于‘ * ’的例子 关于width域宽的例子 关于length长度修饰符的说明 4. 其他常见问题说明 4.1 scanf&#xff08;&#xff09;函数连…

Diffusion扩散模型学习2:DDPM前向加噪过程torch实现

参考: https://arxiv.org/pdf/2006.11239.pdf ##论文 https://github.com/dtransposed/code_videos/blob/main/01_Diffusion_Models_Tutorial/Diffusion%20Model.ipynb ##code https://spaces.ac.cn/archives/9119 1、红色框: 前向过程论文公式推出可以从x0原图一步到最终噪声…

移动神器RAX3000M路由器不刷固件变身家庭云之三:外网访问家庭云

本系列文章&#xff1a; 移动神器RAX3000M路由器变身家庭云之一&#xff1a;开通SSH&#xff0c;安装新软件包 移动神器RAX3000M路由器变身家庭云之二&#xff1a;安装vsftpd 移动神器RAX3000M路由器变身家庭云之三&#xff1a;外网访问家庭云 移动神器RAX3000M路由器变身家庭云…

jetson AGC orin 配置pytorch和cuda使用、yolov8 TensorRt测试

文章目录 1、安装环境1.1、检查系统环境1.2、下载安装pytorch1.3、下载安装torchvision1.3、测试安装是否成功 2、yolov8测试2.1、官方python脚本测试2.2、tensorrt 模型转换2.3、tensorrt c 测试 1、安装环境 1.1、检查系统环境 检查系统环境、安装jetpack版本&#xff0c;执…

Java8升级到Java11注意事项

Java8介绍 Java 8&#xff08;又称为 JDK 1.8&#xff09;是 Java 语言开发的一个主要版本&#xff0c;由 Oracle 公司于2014年3月发布。这个版本引入了大量新特性&#xff0c;包括对函数式编程的支持、新的 JavaScript 引擎、用于日期时间操作的新 API、新的 Steam API 等。 …

Python高级用法:装饰器用于参数检查

装饰器用于参数检查 检查函数接受或返回的参数&#xff0c;在特定上下文中执行时可能有用。XML-RPC协议是一种轻量级的远程过程调用&#xff08;Remote Procedure Call&#xff09;协议&#xff0c;通过HTTP使用XML对调用进行编码。自定义装饰器可以提供这种类型的签名&#x…

Linux操作系统基础(12):Linux的Shell解释器

1. Shell的介绍 在Linux中&#xff0c;Shell 是一种命令行解释器&#xff0c;它是用户与操作系统内核之间的接口&#xff0c;它负责解释用户输入的命令&#xff0c;并将其转换成系统调用或其他操作系统能够执行的指令。 Shell 提供了一种交互式的方式来与操作系统进行通信&am…

内核线程创建-kthread_create

文章参考Linux内核线程kernel thread详解 - 知乎 大概意思就是早期创建内核线程&#xff0c;是交由内核处理&#xff0c;由内核自己完成&#xff08;感觉好像也不太对呢&#xff09;&#xff0c;创建一个内核线程比较麻烦&#xff0c;会导致内核阻塞。因此就诞生了工作队列以及…