【C++11并发】mutex 笔记
简介
在多线程中往往需要访问临界资源,C++11为我们提供了mutex等相关类来保护临界资源,保证某一时刻只有一个线程可以访问临界资源。主要包括各种mutex,他们的命名大都是xx_mutex。以及RAII风格的wrapper类,RAII就是一般在构造的时候上锁,在析构的时候解锁。
C++11提供的锁类型有三个:
- mutex,头文件:
- timed_mutex,头文件:
- recursive_mutex,头文件:
- recursive_timed_mutex,头文件:<shared_mutex>
C++11提供的RAII风格的wrapper类有两个:
- lock_guard,头文件:
- unique_lock,头文件:
std::mutex
mutex提供的方法不过,主要有lock和unlock

mutex只有默认构造方法,不允许拷贝构造,目前也没有提供移动构造
constexpr mutex() noexcept;
mutex( const mutex& ) = delete;
lock和try_lock的区别是,lock会阻塞当前线程,而try_lock不会,如果没有获取到锁,则返回false,如果获取到则返回true。
std::timed_mutex
相比于mutex,timed_mutex多了try_lock_for和try_lock_until两个方法。try_lock_for表示花多长时间尝试获取锁,如果超过时长则失败。try_lock_until表示尝试获取锁到什么时候,如果超过指定时间点则失败。

try_lock_for的函数声明如下,两个模板参数都是形参timeout_duration的,Rep表示保存时间段的类型,Period表示单位,比如秒,毫秒等。详细参考:chrono。try_lock_for表达的意思就是:阻塞获取锁,最长阻塞timeout_duration时间。如果期间获取到了锁,则返回true,否则返回false。如果timeout_duration小于等于0,try_lock_for的行为就和try_lock一样。
template< class Rep, class Period >
bool try_lock_for( const std::chrono::duration<Rep, Period>& timeout_duration );
例子:
#include <iostream>
#include <thread>
#include <mutex>
#include <chrono>void run(std::timed_mutex &mutex)
{if (mutex.try_lock_for(std::chrono::milliseconds(500))) {std::cout << "获得了锁" << std::endl;} else {std::cout << "未获得锁" << std::endl;}
}int main() {std::timed_mutex mutex;mutex.lock();std::thread thread(run, std::ref(mutex));thread.join();mutex.unlock();return 0;
}//输出:未获得锁
try_lock_until的函数声明如下,两个模板参数都是形参timeout_time的,Clock是始终类型,Duration就是前面的std::chrono::duration。try_lock_until表达的意识就是:阻塞获取锁,一直阻塞到timeout_time这个时间点。如果期间获取到了锁,则返回true,否则返回false。time_point 参考。
template< class Clock, class Duration >
bool try_lock_until( const std::chrono::time_point<Clock, Duration>& timeout_time );
例子:
#include <iostream>
#include <thread>
#include <mutex>
#include <chrono>void run(std::timed_mutex &mutex)
{std::chrono::time_point<std::chrono::system_clock> now = std::chrono::system_clock::now();if (mutex.try_lock_for(now + std::chrono::milliseconds(500))) {std::cout << "获得了锁" << std::endl;} else {std::cout << "未获得锁" << std::endl;}
}int main() {std::timed_mutex mutex;mutex.lock();std::thread thread(run, std::ref(mutex));thread.join();mutex.unlock();return 0;
}//输出:未获得锁
std::recursive_mutex
recursive_mutex和mutex的区别就在“recursive“,recursive_mutex允许同一个线程多次lock,当然需要相同次数的unlock。c++没有规定最多可以调用多少次,如果到达了最大lock次数,lock方法会抛出异常(std::system_error),try_lock会返回false。

std::recursive_timed_mutex
recursive_timed_mutex就是recursive_mutex和timed_mutex的结合体,提供的方法如下:

std::lock_guard
lock_guard是一个RAII风格mutex wrapper,即就是在他析构的时候,会解锁他关联的mutex。一般在构造lock_guard的时候,给mutex上锁,当然也有例外,具体得看在调用lock_guard的构造方法时传的参数。
下面是lock_guard提供的方法

构造方法可用的有两个
explicit lock_guard( mutex_type& m ); // 在构造lock_guard的时候调用m的lock方法,在析构的时候调用m的unlock方法
lock_guard( mutex_type& m, std::adopt_lock_t t ); // 只是关联m,但是不调用m的lock方法,在析构的时候调用m的unlock方法
lock_guard( const lock_guard& ) = delete; // 禁止拷贝构造lock_guard
std::unique_lock
相比于lock_guard,unique_lock提供了更强大的功能,虽然不能拷贝,但是可以移动。处理支持mutex的所有操作外,还可以支持mutex延迟上锁,尝试上锁等。lock_guard提供的方法有:

unique_lock提供的构造方法比较多:
unique_lock() noexcept; // 构造一个不关联mutex的unique_lock对象,他可以通过移动拷贝操作符关联到一个mutex,或者调用swap方法
unique_lock( unique_lock&& other ) noexcept; // 移动构造
explicit unique_lock( mutex_type& m ); // 构造unique_lock的时候,调用m.lock()
unique_lock( mutex_type& m, std::defer_lock_t t ) noexcept; // 仅关联m,但是不调用m的lock方法
// 关联m,并且调用m的try_lock方法,当然前提是m有try_lock方法,如果没有,则行为是未定义的。
// try_lock可能失败,返回false。unique_lock的构造方法没有返回值,我们怎么知道m有没有上锁成功。
// 调用unique_lock的owns_lock方法,他返回bool,可以知道m有没有上锁成功。具体可以参考例子
unique_lock( mutex_type& m, std::try_to_lock_t t );
// 关联已经上锁的m,如果m没有上锁,则行为未定义
unique_lock( mutex_type& m, std::adopt_lock_t t );// 构造unique_lock的时候,关联m,并且执行m.try_lock_for(timeout_duration)。
// m上锁有没有成功,仍然可以通过unique_lock的owns_lock方法获取
template< class Rep, class Period >
unique_lock( mutex_type& m, const std::chrono::duration<Rep, Period>& timeout_duration );// 和上一个方法类似,只不过执行的是m.try_lock_until(timeout_time)
template< class Clock, class Duration >
unique_lock( mutex_type& m, const std::chrono::time_point<Clock, Duration>& timeout_time );
try_to_lock的例子:
#include <iostream>
#include <mutex>std::mutex mtx;void fun() {std::unique_lock<std::mutex> guard(mtx, std::try_to_lock);if (m_guard1.owns_lock()) {std::cout << "try_to_lock success" << std::endl;} else {std::cout << "try_to_lock failed" << std::endl;}
}
当unique_lock对象成功关联到了mutex,并且他获得了锁,则在析构的时候调用mutex的unlock方法。
unique_lock仅支持移动拷贝赋值操作符
unique_lock& operator=( unique_lock&& other );
unique_lock还提供了获取mutex的方法,在调用unique_lock提供的各种lock类方法时,就如同mutex()->lock()
mutex_type* mutex() const noexcept;
unique_lock还提供了unlock方法,当调用这个方法的时候,会调用mutex的unlock方法,并且unique_lock释放mutex,即不再关联当前mutex。当时当调用unlock方法时,没有关联到mutex,或者mutex没有获得锁,则会抛出std::system_error异常。
void unlock();
unique_lock的release方法只是与关联的mutex断开关联,并不会调用mutex的unlock方法
mutex_type* release() noexcept;
bool操作符,相当于调用owns_lock(),具体使用参考如下实例:
explicit operator bool() const noexcept;
#include <iostream>
#include <mutex>
#include <thread>class Test {
public:void fun() {std::unique_lock<std::mutex> lck(m_mtx);if (bool(lck)) {std::cout << "lock succ: bool(lck)" << std::endl;}if ((bool)lck) {std::cout << "lock succ: (bool)lck" << std::endl;}if (lck) {std::cout << "lock succ: lck" << std::endl;}}private:std::mutex m_mtx;
};int main() {Test test;std::thread thread(&Test::fun, &test);thread.join();return 0;
}/** 输出结果* lock succ: bool(lck)* lock succ: (bool)lck* lock succ: lck*/
相关文章:
【C++11并发】mutex 笔记
简介 在多线程中往往需要访问临界资源,C11为我们提供了mutex等相关类来保护临界资源,保证某一时刻只有一个线程可以访问临界资源。主要包括各种mutex,他们的命名大都是xx_mutex。以及RAII风格的wrapper类,RAII就是一般在构造的时…...
洛谷 P5635 【CSGRound1】天下第一
原址链接 P5635 【CSGRound1】天下第一 先看标签 搜索?模拟?用不着这么复杂 创建函数a(int x,int y,int p) a(int x,int y,int p){if(x<0){return 1;}x (xy)%p;if(y<0){return 2;}y (xy)%p;return a(x,y,p); }写入主函数 #include<iostrea…...
如何通过Navicat远程访问宝塔面板安装的MySQL数据库
Navicat报错信息: 错误代码 1045 Access denied for user ‘root’’219.144.205.81’ (using password:YES) —— 没有权限的访问的报错 1.宝塔面板 > 放行端口:3306 2.阿里云安全组 > 放行端口:3306 3.配置mysql3306端口 4.使用Xshell 链接服务器 m…...
【硅谷甄选】导航守卫(进度条,网页标题,路由鉴权)
import setting from /setting import router from /router // 任意路由切换实现进度条业务: nprogress插件 import nprogress from nprogress // js插件在ts中的报错 // 引入进度条样式 import nprogress/nprogress.css // 表示在加载进度条时不显示加载小图标 np…...
OpenHarmony—TypeScript到ArkTS约束说明
对象的属性名必须是合法的标识符 规则:arkts-identifiers-as-prop-names 级别:错误 在ArkTS中,对象的属性名不能为数字或字符串。通过属性名访问类的属性,通过数值索引访问数组元素。 TypeScript var x { name: x, 2: 3 };c…...
蓝桥杯——每日一练(简单题)
题目 有n个整数,使前面各数顺序向后移m个位置,最后m个数变成前面m个数。写一函数:实现以上功能,在主函数中输入n个数和输出调整后的n个数。 解析 一、list()函数配合map()函数获得…...
css设置不可点击
文章目录 一、前言二、MDN三、使用四、注意五、总结六、最后 一、前言 在网页开发中,经常会遇到一种情况,就是需要将某个元素的点击事件屏蔽,使其在用户点击时没有任何反应。这时候,我们可以通过CSS的pointer-events属性设置为no…...
fastapi学习
fastapi框架 fastapi,一个用于构建 API 的现代、快速(高性能)的web框架。 fastapi是建立在Starlette和Pydantic基础上的,Pydantic是一个基于Python类型提示来定义数据验证、序列化和文档的库。Starlette是一种轻量级的ASGI框架/工…...
【代码随想录-数组】长度最小的子数组
💝💝💝欢迎来到我的博客,很高兴能够在这里和您见面!希望您在这里可以感受到一份轻松愉快的氛围,不仅可以获得有趣的内容和知识,也可以畅所欲言、分享您的想法和见解。 推荐:kwan 的首页,持续学习,不断总结,共同进步,活到老学到老导航 檀越剑指大厂系列:全面总结 jav…...
多表查询练习题
student表: score表: 向student表插入记录: 向score表插入记录: 1.查询student表的所有记录 SELECT * FROM student;2.查询student表的第2条到4条记录 SELECT * FROM student LIMIT 1,3;3.从student表查询所有学生的学号(id)、姓名(name&…...
SpringBoot之时间数据前端显示格式化
背景 在实际我们通常需要在前端显示对数据操作的时间或者最近的更新时间,如果我们只是简单的使用 LocalDateTime.now()来传入数据不进行任何处理那么我们就会得到非常难看的数据 解决方式: 1). 方式一 在属性上加上注解,对日期进行格式…...
Maven讲解
介绍 Maven是一个流行的构建工具和项目管理工具,它主要用于Java项目的构建、依赖管理和项目报告生成。Maven通过提供一致的项目结构、自动化的构建过程和强大的依赖管理,简化了项目的开发和维护过程。 下面是一些Maven的主要特点和用途: 项…...
Redis2-事务 连接Java 整合springboot 注解缓存
一、订阅和发布 Redis 发布订阅 (pub/sub) 是一种消息通信模式:发送者 (pub) 发送消息,订阅者 (sub) 接收消息。 Redis 客户端可以订阅任意数量的频道。 Redis的发布和订阅 客户端订阅频道发布的消息 频道发布消息 订阅者就可以收到消息 发布订阅的代…...
CHFS 文件服务器搭建小记
一、CHFS 简介 摘自官网:http://iscute.cn/chfs CuteHttpFileServer/chfs 是一个免费的、HTTP协议的文件共享服务器,使用浏览器可以快速访问。它具有以下特点: 单个文件,核心功能无需其他文件跨平台运行,支持主流平台…...
vue中图片不显示问题 - vue中静态资源加载
文章目录 vue中图片不显示问题静态资源URL 转换规则webpack 静态资源处理 图片不显示问题问题描述解决办法1:使用require引入require is not defined 解决办法2:使用import引入解决办法3:将图片放进公共文件夹static或public vue中图片不显示…...
IP报文格式
IP报文格式 报文格式 图1 IP头格式 表1 IP头字段解释 字段长度含义Version4比特 4:表示为IPV4;6:表示为IPV6。IHL4比特首部长度,如果不带Option字段,则为20,最长为60,该值限制了记录路由选项。…...
k8s 进阶实战笔记 | Pod 创建过程详解
Pod 创建过程详解 初始状态0 controller-manager、scheduler、kubelet组件通过 list-watch 机制与 api-server 通信并检查资源变化 第一步 用户通过 CLI 或者 WEB 端等方式向 api-server 发送创建资源的请求(比如:我要创建一个replicaset资源&…...
使用MMYOLO中yolov8训练自己VOC数据集实战
概述 MMYOLO是商汤公司基于PyTorch框架和YOLO系列算法开源的工具箱 - 目前支持的任务 目标检测旋转框目标检测 - 支持的算法 YOLOv5YOLOv6YOLOv7YOLOv8YOLOXRTMDetRTMDet-Rotated - 支持的数据集 COCO Dataset VOC Dataset CrowdHuman Dataset DOTA 1.0 Dataset 安装…...
解决方案 | 基于SFTP协议的文件传输断点续传Java实现方案
背景 因项目需要,我们服务每天都需要通过SFTP协议来对接上下游进行文件传输,但是对于一些大文件,在与第三方公司的服务器对接过程中很可能会因为网络问题或上下游服务器性能问题导致文件上传或者下载被中断,每次重试都需要重新对…...
web前端项目-动画特效【附源码】
文章目录 一:赛车游戏动画HTML源码:JS源码:CSS源码:(1)normalize.css(2)style.css 二:吉普车动画演示HTML源码:CSS源码:(1)…...
51c自动驾驶~合集58
我自己的原文哦~ https://blog.51cto.com/whaosoft/13967107 #CCA-Attention 全局池化局部保留,CCA-Attention为LLM长文本建模带来突破性进展 琶洲实验室、华南理工大学联合推出关键上下文感知注意力机制(CCA-Attention),…...
LeetCode - 394. 字符串解码
题目 394. 字符串解码 - 力扣(LeetCode) 思路 使用两个栈:一个存储重复次数,一个存储字符串 遍历输入字符串: 数字处理:遇到数字时,累积计算重复次数左括号处理:保存当前状态&a…...
【机器视觉】单目测距——运动结构恢复
ps:图是随便找的,为了凑个封面 前言 在前面对光流法进行进一步改进,希望将2D光流推广至3D场景流时,发现2D转3D过程中存在尺度歧义问题,需要补全摄像头拍摄图像中缺失的深度信息,否则解空间不收敛…...
c++ 面试题(1)-----深度优先搜索(DFS)实现
操作系统:ubuntu22.04 IDE:Visual Studio Code 编程语言:C11 题目描述 地上有一个 m 行 n 列的方格,从坐标 [0,0] 起始。一个机器人可以从某一格移动到上下左右四个格子,但不能进入行坐标和列坐标的数位之和大于 k 的格子。 例…...
[ICLR 2022]How Much Can CLIP Benefit Vision-and-Language Tasks?
论文网址:pdf 英文是纯手打的!论文原文的summarizing and paraphrasing。可能会出现难以避免的拼写错误和语法错误,若有发现欢迎评论指正!文章偏向于笔记,谨慎食用 目录 1. 心得 2. 论文逐段精读 2.1. Abstract 2…...
数据链路层的主要功能是什么
数据链路层(OSI模型第2层)的核心功能是在相邻网络节点(如交换机、主机)间提供可靠的数据帧传输服务,主要职责包括: 🔑 核心功能详解: 帧封装与解封装 封装: 将网络层下发…...
【服务器压力测试】本地PC电脑作为服务器运行时出现卡顿和资源紧张(Windows/Linux)
要让本地PC电脑作为服务器运行时出现卡顿和资源紧张的情况,可以通过以下几种方式模拟或触发: 1. 增加CPU负载 运行大量计算密集型任务,例如: 使用多线程循环执行复杂计算(如数学运算、加密解密等)。运行图…...
第 86 场周赛:矩阵中的幻方、钥匙和房间、将数组拆分成斐波那契序列、猜猜这个单词
Q1、[中等] 矩阵中的幻方 1、题目描述 3 x 3 的幻方是一个填充有 从 1 到 9 的不同数字的 3 x 3 矩阵,其中每行,每列以及两条对角线上的各数之和都相等。 给定一个由整数组成的row x col 的 grid,其中有多少个 3 3 的 “幻方” 子矩阵&am…...
全面解析各类VPN技术:GRE、IPsec、L2TP、SSL与MPLS VPN对比
目录 引言 VPN技术概述 GRE VPN 3.1 GRE封装结构 3.2 GRE的应用场景 GRE over IPsec 4.1 GRE over IPsec封装结构 4.2 为什么使用GRE over IPsec? IPsec VPN 5.1 IPsec传输模式(Transport Mode) 5.2 IPsec隧道模式(Tunne…...
如何在最短时间内提升打ctf(web)的水平?
刚刚刷完2遍 bugku 的 web 题,前来答题。 每个人对刷题理解是不同,有的人是看了writeup就等于刷了,有的人是收藏了writeup就等于刷了,有的人是跟着writeup做了一遍就等于刷了,还有的人是独立思考做了一遍就等于刷了。…...
