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
的主要特点和用法:
-
共享锁(Shared Lock):
- 多个线程可以同时获得共享锁,这允许它们并发地读取共享资源。
- 共享锁使用
std::shared_lock
来获取。
#include <shared_mutex>std::shared_mutex mySharedMutex;void readOperation() {std::shared_lock<std::shared_mutex> lock(mySharedMutex);// 读取共享资源的代码 }
-
独占锁(Exclusive Lock):
- 只有一个线程可以获得独占锁,这使得它能够独占地修改共享资源。
- 独占锁使用
std::unique_lock
来获取。
#include <shared_mutex>std::shared_mutex mySharedMutex;void writeOperation() {std::unique_lock<std::shared_mutex> lock(mySharedMutex);// 修改共享资源的代码 }
-
避免写者饥饿(Writer Starvation Avoidance):
std::shared_mutex
的设计旨在避免写者饥饿问题,即允许读者和写者以公平的方式争夺锁。
-
适用于读多写少的场景:
std::shared_mutex
在读多写少的情况下表现得较为优越,因为多个线程可以同时获得共享锁,提高了并发性能。
-
注意事项:
- 使用
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::mutex
,std::unique_lock
,std::recursive_mutex
,和 std::shared_mutex
的特点进行比较的表格:
特点 | std::mutex | std::unique_lock | std::recursive_mutex | std::shared_mutex |
---|---|---|---|---|
类型 | 互斥锁 | 可锁定、可解锁的锁 | 递归互斥锁 | 共享/独占互斥锁 |
RAII 风格 | 有(使用 std::lock_guard ) | 有 | 有 | 有(std::unique_lock ) |
支持条件变量 | 不支持 | 支持 | 不支持 | 支持 |
是否支持递归 | 不支持 | 不支持 | 支持 | 不支持 |
多线程性能 | 适用于大多数场景,较轻量级 | 较为灵活,适用于复杂的场景 | 适用于需要递归锁的场景 | 适用于读多写少的场景 |
锁定粒度 | 整个作用域内的代码 | 可以在较小的范围内进行锁定和解锁 | 整个作用域内的代码 | 可以同时支持独占和共享访问 |
死锁风险 | 高(如果未正确解锁,可能导致死锁) | 低(通过 std::lock() 可以避免死锁) | 递归锁允许同一线程多次获取锁,小心死锁风险 | 低(支持共享和独占访问,适当使用可以减少死锁风险) |
内存开销 | 低(较为轻量级) | 较高(提供了更多的功能) | 较高(需要额外的信息来支持递归锁) | 较高(需要维护更多状态信息) |
这个比较表格总结了这些锁的主要特点,但具体的选择取决于你的应用场景和需求。通常来说,std::mutex
是最基本的锁,而 std::unique_lock
提供了更多的灵活性,特别是在需要支持条件变量的情况下。std::recursive_mutex
对于需要在同一线程中多次获取锁的递归情况很有用。std::shared_mutex
则适用于读多写少的场景,提供了更好的并发性能。
相关文章:
c++,mutex,unique_lock,recursive_mutex,shared_mutex对比分析
当处理多线程并发时,正确使用锁是确保线程安全的关键。 1. std::mutex(互斥锁): std::mutex 是C标准库提供的最基本的锁。它的基本使用如下: #include <iostream> #include <mutex> #include <threa…...
MySQL与Oracle数据库在网络安全等级方面用到的命令
MySQL数据库命令集 查看数据库版本 SELECT VERSION(); 空口令查询 SELECT user,host,account_locked FROM mysql.user WHERE user ; SELECT * FROM mysql.user; 查询 用户的密码加密情况 SELECT HOST,USER,PLUGIN FROM mysql.user; 查询是否有空用户 SELECT host,user,plug…...
MySQL——视图
目录 一.视图介绍 二.基本使用 三.视图规则和限制 一.视图介绍 视图是一个虚拟表,其内容由查询定义。同真实的表一样,视图包含一系列带有名称的列和行数据。视图的数据变化会影响到基表,基表的数据变化也会影响到视图。 二.基本使用 创…...
【响应式编程-03】Lambda表达式底层实现原理
一、简要描述 Lambda的底层实现原理Lambda表达式编译和运行过程 二、Lambda的底层实现原理 Lambda表达式的本质 函数式接口的匿名子类的匿名对象 反编译:cfr-0.145.jar 反编译:LambdaMetafactory.metafactory() 跟踪调试,转储Lambda类&#x…...
深入理解可变参数
1.C语言方式 目录 1.C语言方式 1.1.宏介绍 1.2.原理详解 1.3.宏的可变参数 1.4.案例分析 1.5.其他实例 2.C之std::initializer_list 2.1.简介 2.2.原理详解 2.3.案例分析 3.C之可变参数模版 3.1.简介 3.2.可变参数个数 3.3.递归包展开 3.4.逗号表达式展开 3.5…...
Centos7.9和Debian12部署Minio详细流程
一、安装minio Centos wget https://dl.min.io/server/minio/release/linux-amd64/archive/minio-20230227181045.0.0.x86_64.rpm -O minio.rpm sudo dnf install minio.rpmDebian wget https://dl.min.io/server/minio/release/linux-amd64/archive/minio_20230227181045.0…...
软件测试|教你如何使用UPDATE修改数据
简介 在SQL(Structured Query Language)中,UPDATE语句用于修改数据库表中的数据。通过UPDATE语句,我们可以更新表中的特定记录或多条记录,从而实现数据的修改和更新。本文将详细介绍SQL UPDATE语句的语法、用法以及一…...
新闻稿发布:媒体重要还是价格重要
在当今信息爆炸的数字时代,企业推广与品牌塑造不可或缺的一环就是新闻稿发布。新闻稿是一种通过媒体渠道传递企业信息、宣传品牌、事件或产品新闻的文本形式。发布新闻稿的过程旨在将企业的声音传递给更广泛的受众,借助媒体平台实现品牌故事的广泛传播。…...
prometheus grafana mysql监控配置使用
文章目录 前传bitnami/mysqld-exporter:0.15.1镜像出现了问题.my.cnf可以用这个"prom/mysqld-exporter:v0.15.0"镜像重要的事情mysql监控效果外传 前传 prometheus grafana的安装使用:https://nanxiang.blog.csdn.net/article/details/135384541 本文说…...
鸿蒙HarmonyOS-带笔锋手写板(三)
笔者用ArkTS 写了一个简单的带笔锋的手写板应用,并且可以将手写内容保存为图片。 一、效果图 手写效果如下(在鸿蒙手机模拟器上运行,手写时反应可能会有点慢) 二、实现方法 参考文章: 支持笔锋效果的手写签字控件_a…...
React 实现 Step组件
简介 本文将会实现步骤条组件功能。步骤条在以下几个方面改进。 1、将url与Step组件绑定,做到浏览器刷新,不会重定向到Step 1 2、通过LocalStorage 存储之前的Step,做到不丢失数据。 实现 Step.jsx (组件) import {useEffect, useState} fro…...
【OJ】单链表刷题
力扣刷题 1. 反转链表(206)1.1 题目描述1.2 题目分析1.2.1 头插法1.2.2 箭头反转 1.3 题目代码1.3.1 头插入1.3.2 箭头反转 2.合并两个有序链表(21)2.1 题目描述2.2 题目分析2.3 题目代码 1. 反转链表(206)…...
【UML建模】部署图(Deployment Diagram)
1.概述 部署图是一种结构图,用于描述软件系统在不同计算机硬件或设备上的部署和配置情况,以图形化的方式展示系统中组件、节点和连接之间的物理部署关系。 通过部署图,可以清晰地了解系统的物理结构和部署方式,包括系统组件和节…...
三、计算机理论-关系数据库-数据模型与数据视图;关系代数、关系演算及关系模型
数据模型 具体事物-抽象化-->概念模型-数据化-->数据模型 概念模型也称信息模型,在数据库设计阶段,由设计者按照用户的观点对数据和信息建模,实现对现实世界的概念抽象; 数据模型主要包括网状模型、层次模型、关系模型、面向…...
解读 $mash 通证 “Fair Launch” 规则(Staking 玩法解读篇)
Solmash 是 Solana 生态中由社区主导的铭文资产 LaunchPad 平台,该平台旨在为 Solana 原生铭文项目,以及通过其合作伙伴 SoBit 跨链桥桥接到 Solana 的 Bitcoin 生态铭文项目提供更广泛的启动机会。...
【C语言】关于C11的一些新特性
相比于VC 6.0使用的ANSI C标准,VS2022使用的C11标准与上一代有很多不同,相比之前的 C 标准(如 C89/C90 和 C99),引入了一些新的功能、特性和改进。以下是 C11 标准相对于之前版本的一些主要变化和新增内容:…...
牛的速记(c++题解)
题目描述 奶牛们误解了速记的含义。他们是这样理解的: 给出一个少于255个字母的小写字母串。 找到一个出现次数最多的字母,将该字母从字母串中统统删去,如果出现次数最多的字母不止一个,就删去在字母表中靠前的一个,即…...
使用ffmpeg+flv.js + websokect播放rtsp格式视频流
对于rtsp的视频流网上有很多种的解决方案,但是大的趋势还是利用ffmpeg的工具进行rtsp的视频解析进行一个推流,我最终选择bilibili开源的flv.js,代码十分的简单全部都在底层封装好了。实现的方式也比较容易理解,ffmpeg进行rtsp的视…...
OAI openair3代码结构整理
openair3代码框架结构 OAI(OpenAirInterface)是一个开源的5G网络软件平台,用于研究和开发5G网络技术。OpenAir3是OAI项目中的一个子项目,专注于5G核心网络的功能实现。 一、OpenAir3的代码主要包括以下几个部分: NAS…...
Kubernets(K8S)启动和运行 01-01 Kubernetes简介
Kubernets(K8S)启动和运行 01-01 Kubernetes简介 Kubernetes is an open source orchestrator for deploying containerized applications. It was originally developed by Google, inspired by a decade of experience deploying scalable, reliable systems in containers …...
PHP特性知识点扫盲 - 下篇
概述 在实际的生产环境中遇到了实际需要解决的问题,需要把服务部署的方式梳理出来,在同一个服务器中部署多个PHP环境,架构图如下: 架构方案 在工作实践中遇到的很多问题的普遍性都是相通的,公司运行的可新项目都是版…...
HarmonyOS应用开发之DevEco Studio安装与初次使用
1、DevEco Studio介绍 DevEco Studio是基于IntelliJ IDEA Community开源版本打造,面向华为终端全场景多设备的一站式集成开发环境(IDE),为开发者提供工程模板创建、开发、编译、调试、发布等E2E的HarmonyOS应用/服务的开发工具。…...
记录第一次在GitHub上面提交Issue
第一次在GitHub上面提交Issue,记录一下。 对着源码调了好久才发现,问题并不在程序而在模型(虽然只是一个很小的问题,但是能够解决问题,并且做出了自己的一点小小贡献,还是很开心。嘻嘻,发博客记…...
【数据库设计和SQL基础语法】--用户权限管理--数据备份和恢复策略
一、引言 数据备份和恢复是数据库管理中至关重要的任务,对于确保数据安全性和业务连续性具有重大的意义。以下是一些关键的重要性方面: 防止数据丢失: 数据备份是防止因硬件故障、人为错误、恶意攻击或其他意外事件导致数据丢失的主要手段。…...
java数据结构与算法刷题-----LeetCode70. 爬楼梯
java数据结构与算法刷题目录(剑指Offer、LeetCode、ACM)-----主目录-----持续更新(进不去说明我没写完):https://blog.csdn.net/grd_java/article/details/123063846 很多人觉得动态规划很难,但它就是固定套路而已。其实动态规划只…...
【Unity入门】UGUI之Slider(滑动条)
目录 一、什么是Slider?二、Slider属性与功能 一、什么是Slider? Slider控件允许用户可以通过鼠标来在预先确定的范围调节数值 我们可以在Hierarchy视图右键 -> UI ->Slider来创建滑动条 通过上图可以发现Unity内置的Slider主要有3部分&#x…...
MySQL中UNION和UNION ALL的区别有哪些?
在MySQL中如何想要对两个结果集进行合并操作,可以使用UNION和UNION ALL,如果只是想要去除掉重复的记录,属于UNION ALL 即可,但是如何想要除掉没有重复行数据,就要使用Union。本文详细向大家介绍MySQL中UNION和UNION AL…...
Android kotlin build.gradle.kts配置
1. 添加 maven 仓库 1. 1. settings配置 1. 1.1. settings.gradle repositories {maven {url https://maven.aliyun.com/repository/public/}mavenCentral() }1. 1.2. settings.gradle.kts repositories {maven {setUrl("https://maven.aliyun.com/repository/public/…...
css、js、vue常考部分面试题
css css盒子水平垂直居中方法 方法一:定位 .child{height: 100px;position: absolute;//父元素相对定位top:50%;left:50%;transform: translate(-50%,-50%); } 方法二:定位 .child{width: 100px;height: 100px;position: absolute;top:50%;left:50%…...
OpenAI ChatGPT-4开发笔记2024-03:Chat之Function Calling/Function/Tool/Tool_Choice
Updates on Function Calling were a major highlight at OpenAI DevDay. In another world,原来的function call都不再正常工作了,必须全部重写。 function和function call全部由tool和tool_choice取代。2023年11月之前关于function call的代码都准备翘翘。 干嘛…...
html做调查问卷网站/360网站推广客服电话
HTML(javascript)或其他静态html技术中是否有能够:停止页面加载(如果浏览器尚未下载)停止页面渲染(从放置代码的位置开始)停止执行javascript(从放置代码的位置开始)简单地说,是否有类似的代码window.StopWhateverBelow()让浏览器完全忽略代码下面的内容…...
网站建设的空间是什么意思/广告商对接平台
Elasticsearch 是一个非常强大的搜索引擎。它目前被广泛地使用于各个IT公司。Elasticsearch 是由 Elastic 公司创建并开源维护的。它的开源代码位于 https://github.com/elastic/elasticsearch。同时,Elastic 公司也拥有 Logstash 及 Kibana 开源项目。这个三个开源…...
公共资源交易网站建设方案/种子资源
PS:用代码画点这样写是为了跟后面的用鼠标画点线面区分出来画点drawPointGraphic: function () {//点有多种样式:一般的点,显示文字,显示图片//一般的点let wkt "POINT(113.566806 22.22445)";//样式//PS:其…...
深圳公司网站推广/百度基木鱼建站
universal reference If a variable or parameter is declared to have type T&& for some deduced type T, that variable or parameter is a universal reference. 如果一个变量或参数声明为T&&类型,且T为推导类型,则这个变量或者参数…...
网站建设与管理教学视频教程/哪里搜索引擎优化好
交通能力测定分为三个层次,航空、公路、铁路,每个层次的测算方法相同。涉及到若干指标 1.铁路 首先在网络上爬取47个节点之间的铁路关系,这里以运输时间为关系值,得到47*47的无权矩阵G和加权矩阵W 代入UCINET进行中心性分析 无权网…...
那里可以做PC28网站的/一网信息一个简单便捷的新闻网站
点击上方“iOS开发”,选择“置顶公众号”关键时刻,第一时间送达!iOS 通过 runtime 的 API 可以给分类添加属性,关联属性总共有下边3个 API///获取某个对象的关联属性id objc_getAssociatedObject(id object, const void *key) { return _o…...