【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)…...
Spring Boot 实现流式响应(兼容 2.7.x)
在实际开发中,我们可能会遇到一些流式数据处理的场景,比如接收来自上游接口的 Server-Sent Events(SSE) 或 流式 JSON 内容,并将其原样中转给前端页面或客户端。这种情况下,传统的 RestTemplate 缓存机制会…...
基于Docker Compose部署Java微服务项目
一. 创建根项目 根项目(父项目)主要用于依赖管理 一些需要注意的点: 打包方式需要为 pom<modules>里需要注册子模块不要引入maven的打包插件,否则打包时会出问题 <?xml version"1.0" encoding"UTF-8…...
[Java恶补day16] 238.除自身以外数组的乘积
给你一个整数数组 nums,返回 数组 answer ,其中 answer[i] 等于 nums 中除 nums[i] 之外其余各元素的乘积 。 题目数据 保证 数组 nums之中任意元素的全部前缀元素和后缀的乘积都在 32 位 整数范围内。 请 不要使用除法,且在 O(n) 时间复杂度…...
CVE-2020-17519源码分析与漏洞复现(Flink 任意文件读取)
漏洞概览 漏洞名称:Apache Flink REST API 任意文件读取漏洞CVE编号:CVE-2020-17519CVSS评分:7.5影响版本:Apache Flink 1.11.0、1.11.1、1.11.2修复版本:≥ 1.11.3 或 ≥ 1.12.0漏洞类型:路径遍历&#x…...
动态 Web 开发技术入门篇
一、HTTP 协议核心 1.1 HTTP 基础 协议全称 :HyperText Transfer Protocol(超文本传输协议) 默认端口 :HTTP 使用 80 端口,HTTPS 使用 443 端口。 请求方法 : GET :用于获取资源,…...
【JavaSE】多线程基础学习笔记
多线程基础 -线程相关概念 程序(Program) 是为完成特定任务、用某种语言编写的一组指令的集合简单的说:就是我们写的代码 进程 进程是指运行中的程序,比如我们使用QQ,就启动了一个进程,操作系统就会为该进程分配内存…...
安卓基础(Java 和 Gradle 版本)
1. 设置项目的 JDK 版本 方法1:通过 Project Structure File → Project Structure... (或按 CtrlAltShiftS) 左侧选择 SDK Location 在 Gradle Settings 部分,设置 Gradle JDK 方法2:通过 Settings File → Settings... (或 CtrlAltS)…...
SQL Server 触发器调用存储过程实现发送 HTTP 请求
文章目录 需求分析解决第 1 步:前置条件,启用 OLE 自动化方式 1:使用 SQL 实现启用 OLE 自动化方式 2:Sql Server 2005启动OLE自动化方式 3:Sql Server 2008启动OLE自动化第 2 步:创建存储过程第 3 步:创建触发器扩展 - 如何调试?第 1 步:登录 SQL Server 2008第 2 步…...
Monorepo架构: Nx Cloud 扩展能力与缓存加速
借助 Nx Cloud 实现项目协同与加速构建 1 ) 缓存工作原理分析 在了解了本地缓存和远程缓存之后,我们来探究缓存是如何工作的。以计算文件的哈希串为例,若后续运行任务时文件哈希串未变,系统会直接使用对应的输出和制品文件。 2 …...
RabbitMQ 各类交换机
为什么要用交换机? 交换机用来路由消息。如果直发队列,这个消息就被处理消失了,那别的队列也需要这个消息怎么办?那就要用到交换机 交换机类型 1,fanout:广播 特点 广播所有消息:将消息…...
