当前位置: 首页 > news >正文

【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 笔记

简介 在多线程中往往需要访问临界资源&#xff0c;C11为我们提供了mutex等相关类来保护临界资源&#xff0c;保证某一时刻只有一个线程可以访问临界资源。主要包括各种mutex&#xff0c;他们的命名大都是xx_mutex。以及RAII风格的wrapper类&#xff0c;RAII就是一般在构造的时…...

洛谷 P5635 【CSGRound1】天下第一

原址链接 P5635 【CSGRound1】天下第一 先看标签 搜索&#xff1f;模拟&#xff1f;用不着这么复杂 创建函数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报错信息&#xff1a; 错误代码 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 // 任意路由切换实现进度条业务&#xff1a; nprogress插件 import nprogress from nprogress // js插件在ts中的报错 // 引入进度条样式 import nprogress/nprogress.css // 表示在加载进度条时不显示加载小图标 np…...

OpenHarmony—TypeScript到ArkTS约束说明

对象的属性名必须是合法的标识符 规则&#xff1a;arkts-identifiers-as-prop-names 级别&#xff1a;错误 在ArkTS中&#xff0c;对象的属性名不能为数字或字符串。通过属性名访问类的属性&#xff0c;通过数值索引访问数组元素。 TypeScript var x { name: x, 2: 3 };c…...

蓝桥杯——每日一练(简单题)

题目 有n个整数&#xff0c;使前面各数顺序向后移m个位置&#xff0c;最后m个数变成前面m个数。写一函数&#xff1a;实现以上功能&#xff0c;在主函数中输入n个数和输出调整后的n个数。 解析 一、list&#xff08;&#xff09;函数配合map&#xff08;&#xff09;函数获得…...

css设置不可点击

文章目录 一、前言二、MDN三、使用四、注意五、总结六、最后 一、前言 在网页开发中&#xff0c;经常会遇到一种情况&#xff0c;就是需要将某个元素的点击事件屏蔽&#xff0c;使其在用户点击时没有任何反应。这时候&#xff0c;我们可以通过CSS的pointer-events属性设置为no…...

fastapi学习

fastapi框架 fastapi&#xff0c;一个用于构建 API 的现代、快速&#xff08;高性能&#xff09;的web框架。 fastapi是建立在Starlette和Pydantic基础上的&#xff0c;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表查询所有学生的学号&#xff08;id&#xff09;、姓名&#xff08;name&…...

SpringBoot之时间数据前端显示格式化

背景 在实际我们通常需要在前端显示对数据操作的时间或者最近的更新时间&#xff0c;如果我们只是简单的使用 LocalDateTime.now()来传入数据不进行任何处理那么我们就会得到非常难看的数据 解决方式&#xff1a; 1). 方式一 在属性上加上注解&#xff0c;对日期进行格式…...

Maven讲解

介绍 Maven是一个流行的构建工具和项目管理工具&#xff0c;它主要用于Java项目的构建、依赖管理和项目报告生成。Maven通过提供一致的项目结构、自动化的构建过程和强大的依赖管理&#xff0c;简化了项目的开发和维护过程。 下面是一些Maven的主要特点和用途&#xff1a; 项…...

Redis2-事务 连接Java 整合springboot 注解缓存

一、订阅和发布 Redis 发布订阅 (pub/sub) 是一种消息通信模式&#xff1a;发送者 (pub) 发送消息&#xff0c;订阅者 (sub) 接收消息。 Redis 客户端可以订阅任意数量的频道。 Redis的发布和订阅 客户端订阅频道发布的消息 频道发布消息 订阅者就可以收到消息 发布订阅的代…...

CHFS 文件服务器搭建小记

一、CHFS 简介 摘自官网&#xff1a;http://iscute.cn/chfs CuteHttpFileServer/chfs 是一个免费的、HTTP协议的文件共享服务器&#xff0c;使用浏览器可以快速访问。它具有以下特点&#xff1a; 单个文件&#xff0c;核心功能无需其他文件跨平台运行&#xff0c;支持主流平台…...

vue中图片不显示问题 - vue中静态资源加载

文章目录 vue中图片不显示问题静态资源URL 转换规则webpack 静态资源处理 图片不显示问题问题描述解决办法1&#xff1a;使用require引入require is not defined 解决办法2&#xff1a;使用import引入解决办法3&#xff1a;将图片放进公共文件夹static或public vue中图片不显示…...

IP报文格式

IP报文格式 报文格式 图1 IP头格式 表1 IP头字段解释 字段长度含义Version4比特 4&#xff1a;表示为IPV4&#xff1b;6&#xff1a;表示为IPV6。IHL4比特首部长度&#xff0c;如果不带Option字段&#xff0c;则为20&#xff0c;最长为60&#xff0c;该值限制了记录路由选项。…...

k8s 进阶实战笔记 | Pod 创建过程详解

Pod 创建过程详解 ​ 初始状态0 controller-manager、scheduler、kubelet组件通过 list-watch 机制与 api-server 通信并检查资源变化 第一步 用户通过 CLI 或者 WEB 端等方式向 api-server 发送创建资源的请求&#xff08;比如&#xff1a;我要创建一个replicaset资源&…...

使用MMYOLO中yolov8训练自己VOC数据集实战

概述 MMYOLO是商汤公司基于PyTorch框架和YOLO系列算法开源的工具箱 - 目前支持的任务 目标检测旋转框目标检测 - 支持的算法 YOLOv5YOLOv6YOLOv7YOLOv8YOLOXRTMDetRTMDet-Rotated - 支持的数据集 COCO Dataset VOC Dataset CrowdHuman Dataset DOTA 1.0 Dataset 安装…...

解决方案 | 基于SFTP协议的文件传输断点续传Java实现方案

背景 因项目需要&#xff0c;我们服务每天都需要通过SFTP协议来对接上下游进行文件传输&#xff0c;但是对于一些大文件&#xff0c;在与第三方公司的服务器对接过程中很可能会因为网络问题或上下游服务器性能问题导致文件上传或者下载被中断&#xff0c;每次重试都需要重新对…...

web前端项目-动画特效【附源码】

文章目录 一&#xff1a;赛车游戏动画HTML源码&#xff1a;JS源码&#xff1a;CSS源码&#xff1a;&#xff08;1&#xff09;normalize.css&#xff08;2&#xff09;style.css 二&#xff1a;吉普车动画演示HTML源码&#xff1a;CSS源码&#xff1a;&#xff08;1&#xff09…...

Flask RESTful 示例

目录 1. 环境准备2. 安装依赖3. 修改main.py4. 运行应用5. API使用示例获取所有任务获取单个任务创建新任务更新任务删除任务 中文乱码问题&#xff1a; 下面创建一个简单的Flask RESTful API示例。首先&#xff0c;我们需要创建环境&#xff0c;安装必要的依赖&#xff0c;然后…...

【kafka】Golang实现分布式Masscan任务调度系统

要求&#xff1a; 输出两个程序&#xff0c;一个命令行程序&#xff08;命令行参数用flag&#xff09;和一个服务端程序。 命令行程序支持通过命令行参数配置下发IP或IP段、端口、扫描带宽&#xff0c;然后将消息推送到kafka里面。 服务端程序&#xff1a; 从kafka消费者接收…...

MySQL 隔离级别:脏读、幻读及不可重复读的原理与示例

一、MySQL 隔离级别 MySQL 提供了四种隔离级别,用于控制事务之间的并发访问以及数据的可见性,不同隔离级别对脏读、幻读、不可重复读这几种并发数据问题有着不同的处理方式,具体如下: 隔离级别脏读不可重复读幻读性能特点及锁机制读未提交(READ UNCOMMITTED)允许出现允许…...

Java多线程实现之Callable接口深度解析

Java多线程实现之Callable接口深度解析 一、Callable接口概述1.1 接口定义1.2 与Runnable接口的对比1.3 Future接口与FutureTask类 二、Callable接口的基本使用方法2.1 传统方式实现Callable接口2.2 使用Lambda表达式简化Callable实现2.3 使用FutureTask类执行Callable任务 三、…...

【开发技术】.Net使用FFmpeg视频特定帧上绘制内容

目录 一、目的 二、解决方案 2.1 什么是FFmpeg 2.2 FFmpeg主要功能 2.3 使用Xabe.FFmpeg调用FFmpeg功能 2.4 使用 FFmpeg 的 drawbox 滤镜来绘制 ROI 三、总结 一、目的 当前市场上有很多目标检测智能识别的相关算法&#xff0c;当前调用一个医疗行业的AI识别算法后返回…...

稳定币的深度剖析与展望

一、引言 在当今数字化浪潮席卷全球的时代&#xff0c;加密货币作为一种新兴的金融现象&#xff0c;正以前所未有的速度改变着我们对传统货币和金融体系的认知。然而&#xff0c;加密货币市场的高度波动性却成为了其广泛应用和普及的一大障碍。在这样的背景下&#xff0c;稳定…...

C# 求圆面积的程序(Program to find area of a circle)

给定半径r&#xff0c;求圆的面积。圆的面积应精确到小数点后5位。 例子&#xff1a; 输入&#xff1a;r 5 输出&#xff1a;78.53982 解释&#xff1a;由于面积 PI * r * r 3.14159265358979323846 * 5 * 5 78.53982&#xff0c;因为我们只保留小数点后 5 位数字。 输…...

算法笔记2

1.字符串拼接最好用StringBuilder&#xff0c;不用String 2.创建List<>类型的数组并创建内存 List arr[] new ArrayList[26]; Arrays.setAll(arr, i -> new ArrayList<>()); 3.去掉首尾空格...

【Redis】笔记|第8节|大厂高并发缓存架构实战与优化

缓存架构 代码结构 代码详情 功能点&#xff1a; 多级缓存&#xff0c;先查本地缓存&#xff0c;再查Redis&#xff0c;最后才查数据库热点数据重建逻辑使用分布式锁&#xff0c;二次查询更新缓存采用读写锁提升性能采用Redis的发布订阅机制通知所有实例更新本地缓存适用读多…...

在Mathematica中实现Newton-Raphson迭代的收敛时间算法(一般三次多项式)

考察一般的三次多项式&#xff0c;以r为参数&#xff1a; p[z_, r_] : z^3 (r - 1) z - r; roots[r_] : z /. Solve[p[z, r] 0, z]&#xff1b; 此多项式的根为&#xff1a; 尽管看起来这个多项式是特殊的&#xff0c;其实一般的三次多项式都是可以通过线性变换化为这个形式…...