C++多线程:unique_lock源码分析与使用详解(六)

1、unique_lock介绍
  • unique_lock取代lock_guard,unique_lock更像lock_guard的升级版,也是mutex的管家!

  • unique_lock是个类模板,工作中一般使用lock_guard(推荐使用)

    • lock_guard取代了mutex的lock()和unlock()
  • unique_lock比lock_guard灵活很多,效率差一点,内存占用多一点

    • lock_guard额外参数只能传入std::adopt_lock
    • unique_lock额外参数可以传入std::adopt_lock、std::try_to_lock、std::defer_lock…
  • 额外参数的解释

    • std::adopt_lock:标记作用,通知lock_guard或unique_lock不需要再构造函数中lock(),标记的效果就是“假设调用方线程已经拥有了互斥的所有权(已经lock()成功了)”
    • std::try_to_lock:尝试获取锁,如果获取失败将不会阻塞在锁头上,会继续向下执行
    • std::defer_lock:初始化一个没有加锁的mutex

源码参数分析

template<typename _Mutex>
class unique_lock {
public:typedef _Mutex mutex_type;unique_lock() noexcept: _M_device(0), _M_owns(false) {}explicit unique_lock(mutex_type &__m): _M_device(std::__addressof(__m)), _M_owns(false) {lock();_M_owns = true;}unique_lock(mutex_type &__m, defer_lock_t) noexcept: _M_device(std::__addressof(__m)), _M_owns(false) {}unique_lock(mutex_type &__m, try_to_lock_t): _M_device(std::__addressof(__m)), _M_owns(_M_device->try_lock()) {}unique_lock(mutex_type &__m, adopt_lock_t) noexcept: _M_device(std::__addressof(__m)), _M_owns(true) {// XXX calling thread owns mutex}template<typename _Clock, typename _Duration>unique_lock(mutex_type &__m,const chrono::time_point <_Clock, _Duration> &__atime): _M_device(std::__addressof(__m)),_M_owns(_M_device->try_lock_until(__atime)) {}template<typename _Rep, typename _Period>unique_lock(mutex_type &__m,const chrono::duration <_Rep, _Period> &__rtime): _M_device(std::__addressof(__m)),_M_owns(_M_device->try_lock_for(__rtime)) {}~unique_lock() {if (_M_owns)unlock();}
};
  • unique_lock()构造:获取一把空锁,所有权也拿不到为false。
  • unique_lock(mutex_type &__m)构造:传入一个互斥量作为构造参数,然后加锁,持有权为true
  • unique_lock(mutex_type &__m, adopt_lock_t)构造:传入mutex和std::adopt_lock,不在加锁,但是持有权默认为true
  • unique_lock(mutex_type &__m, try_to_lock_t)构造:传入mutex和std::try_to_lock,尝试加锁,持有权为尝试加锁的结果
  • unique_lock(mutex_type &__m, defer_lock_t) 构造:传入mutex和std::defer_lock,传入一把锁但不加锁,持有权为false
  • 另外下面几个带chrono的构造表示睡眠的时间构造。
  • 析构函数很特别:析构函数里写的如果持有锁那么就释放锁,如果不持有锁那么就不释放锁。因此如果我们提前释放锁,那么它不释放

看完上面的构造源码和析构源码,那么下面使用这些参数和构造方法也是一件非常简单的事情了!

2、std::adopt_lock
std::mutex mutex_lock;mutex_lock.lock();
std::unique_lock<std::mutex>(mutex_lock, std::adopt_lock);

std::adopt_lock的含义是高速unique_lock不需要你再去加锁,因此需要手动去加锁,否则没有效果,如上面构造源码。

3、std::try_to_lock的使用
  • 尝试用mutex的lock()去锁定这个mutex,如果没有锁成功也会立即返回并不会阻塞在锁头上,前提是不能先lock()
  • out方法中对线程进行抱着锁睡2秒
  • 如果当执行poll_msg函数的线程1先拿到锁,那么线程2可能在队列中一个元素也不会放进去。因为一旦获取锁失败,循环将继续向下走。
  • 如果线程2先拿到锁,在一个时间片内(具体多久看操作系统的调度)会尽可能的多次获取到锁尝试放入元素。
void inMsgRecvQueue(){for(int i = 0;i < n;i++){// 尝试获取锁std::unique_lock<std::mutex> uniqueLock(mutex_lock, std::try_to_lock);if(uniqueLock.owns_lock()){q.push(i);std::cout << "inMsgRecvQueue()执行, 插入一个元素i = " << i << std::endl;}}
}int poll_msg(){int msg = -1;std::unique_lock<std::mutex> uniqueLock(mutex_lock, std::try_to_lock);std::chrono::milliseconds duration(2000);std::this_thread::sleep_for(duration);std::cout << "queue size = " << q.size() << std::endl;if(q.size()) {msg = q.front();q.pop();}return msg;
}
3、std::defer_lock的使用
  • 这个参数的构造函数很有趣,将unique_lock与mutex绑定在一起,但是没有加锁也没有持有权。

  • 但是我们可以通过unique_lock提供的函数去加锁、解锁、尝试锁…

std::unique_lock<std::mutex> uniqueLock(mutex_lock, std::defer_lock);
uniqueLock.lock();							//  加锁
uniqueLock.owns_lock();				// 是否持有锁:有返回true,否则返回false
uniqueLock.unlock();					// 解锁
std::mutex *ptr = uniqueLock.release();					// 将unique_lock与mutex解除绑定,并且返回指向mutex的指针
uniqueLock.try_lock();					// 尝试获取锁,成功true,失败false
uniqueLock.mutex();						// 返回unique_lock绑定的mutex对象
  • 其实unique_lock传入defer_lock只是进行了一层封装,上面这些加锁解锁的函数mutex也有。

  • 提供这些函数可以很灵活的控制临界区的大小,也就是程序的粒度大小,粒度越细程序越快。

4、unique_lock所有权的传递

其实unique_lock中还有下面几个拷贝构造和赋值=运算符的重载

unique_lock(const unique_lock&) = delete;
unique_lock& operator=(const unique_lock&) = delete;unique_lock(unique_lock&& __u) noexcept : _M_device(__u._M_device), _M_owns(__u._M_owns){__u._M_device = 0;__u._M_owns = false;
}unique_lock& operator=(unique_lock&& __u) noexcept{if(_M_owns)unlock();unique_lock(std::move(__u)).swap(*this);__u._M_device = 0;__u._M_owns = false;return *this
  • unique_lock(unique_lock&& __u) :这是一个锁的移动构造,如果传入一把锁mutex进来,然后交给当前unique_lock持有,原先的unique_lock不在持有这把锁

    // 1
    std::unique_lock<std::mutex> uniqueLock1(mutex_lock);
    std::unique_lock<std::mutex> uniqueLock2(std::move(uniqueLock1));// 2
    std::unique_lock<std::mutex> return_unique_lock(){std::unique_lock<std::mutex> uniqueLock(mutex_lock);return uniqueLock;
    }std::unique_lock<std::mutex> uniqueLock = return_unique_lock();
    

    最后uniqueLock2持有mutex_lock,uniqueLock1不再持有

  • unique_lock& operator=(unique_lock&& __u) :这是一个返回类型为引用的赋值函数重载,如果有可能将原先持有的解锁,然后拿到传入进来的锁,并且将当前的锁返回,返回的是一个引用,因此还可以继续链式编程,但是这个方法已经废弃…

    std::unique_lock<std::mutex> uniqueLock1(mutex_lock);
    std::unique_lock<std::mutex> uniqueLock2(mutex_lock);//        uniqueLock2 = uniqueLock1;
    //        uniqueLock1.operator=(uniqueLock2);
    

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

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

相关文章

Gromacs模拟一:配体-双链蛋白质复合物体系准备

1、蛋白质的准备&#xff1a; 在RCSB网站下载想要的蛋白晶体&#xff08;教程里是3htb&#xff09;&#xff0c;用notepad等编辑器或是分子可视化软件除去里面的非蛋白分子或离子。 这里采用的是一个经过分子对接后的蛋白质pdb和配体小分子的pdb。 教程里提到的配体是2-丙基…

【Java多线程】5——Lock底层原理

5 Lock底层原理 ⭐⭐⭐⭐⭐⭐ Github主页&#x1f449;https://github.com/A-BigTree 笔记仓库&#x1f449;https://github.com/A-BigTree/tree-learning-notes 个人主页&#x1f449;https://www.abigtree.top ⭐⭐⭐⭐⭐⭐ 如果可以&#xff0c;麻烦各位看官顺手点个star~&…

新能源汽车充电桩常见类型及充电桩站场的智能监管方案

随着新能源汽车市场的迅猛发展&#xff0c;充电桩作为支持其运行的基础设施&#xff0c;也呈现出多样化的类型。这些充电桩不仅在外形和功能上存在差异&#xff0c;更在充电速度、充电方式以及使用场景等方面展现出独特的优势。 一、充电桩类型及区别 1、慢充桩&#xff08;交…

C语言经典例题(14) --- 反斜线形图案、正斜线形图案、X形图案、空心正方形图案、空心三角形图案

1.反斜线形图案 题目描述: KK学习了循环&#xff0c;BoBo老师给他出了一系列打印图案的练习&#xff0c;该任务是打印用“*”组成的反斜线形图案。 输入描述: 多组输入&#xff0c;一个整数&#xff08;2~20&#xff09;&#xff0c;表示输出的行数&#xff0c;也表示组成反…

Go 之 Gin 框架

Gin 是一个 Go (Golang) 编写的轻量级 web 框架&#xff0c;运行速度非常快&#xff0c;擅长 Api 接口的高并发&#xff0c;如果项目的规模不大&#xff0c;业务相对简单&#xff0c;这个时候我们也推荐您使用 Gin&#xff0c;特别适合微服务框架。 简单路由配置 package mai…

Linux查看当前目录并输出到文件

进入想要查看的目录 rootubuntu20:/# ls bin boot cdrom dev etc home lib lib32 lib64 libx32 lostfound media mmkv.default mmkv.default.crc mnt opt path proc root run sbin snap srv swapfile sys tmp usr var执行命令 ls -d */ | tr -d /…

Linux 系统快速安装 nginx (新手版)

1、安装所需依赖 yum -y install pcre pcre-devel gcc openssl openssl-devel zlib zlib-devel &#xff08;pcre&#xff1a; 包括 perl 兼容的正则表达式库 openssl&#xff1a; 支持安全传输协议https(和财务有关系的请求会走的协议) 创建运行用户、组 useradd -M -…

变分信息瓶颈

变分信息瓶颈和互信息的定义 1 变分信息瓶颈 定义&#xff1a;变分信息瓶颈&#xff08;Variational Information Bottleneck&#xff09;是一种用于学习数据表示的方法&#xff0c;它旨在通过最小化输入和表示之间的互信息来实现数据的压缩和表示学习。这种方法通常用于无监…

clickhouse 查询group 分组最大值的一行数据。

按照 sql_finger_md5 分组取query_time_ms 最大的一行数据。 使用any函数可以去匹配到的第一行数据&#xff0c;所以可以先让数据按照query_time_ms 排序&#xff0c;然后再使用group by 和any结合取第一行数据&#xff0c;就是最大值的那一行数据。 selectany (time) as time…

JavaScript学习笔记

本篇文章是本人在学习JS时所记录的笔记&#xff0c;记录的知识点比较基础&#xff0c;但是较为详细。 使用 在html中有两种方式可以使用javascript 1.外引 <script src"...js"></script> 调用js文件时调用的是拷贝体 2.内嵌 <script>......…

【BlossomRPC】服务端与客户端请求Handler

文章目录 客户端Handler服务端Handler RPC项目 配置中心项目 网关项目 客户端Handler 承接上文&#xff0c;客户端的Handler其实就比较简单了&#xff0c;因为客户端作为接收数据的时候&#xff0c;我们只需要从上文提到的Cache中通过reqId的方式拿到Future/Promise对象&…

接口自动化框架搭建(一):框架介绍

1&#xff0c;背景目的 最近在搭建接口自动化框架&#xff0c;打算写个专栏&#xff0c;方便自己查找和他人学习。有不正确的地方&#xff0c;欢迎指正。 2&#xff0c;技术框架 pythonpytestalllurejenkins多进程钉钉消息通知 3&#xff0c;版本 推荐方法&#xff1a;创建…

【数据结构与算法】排序

概述 最容易想到的排序&#xff0c;从旧数组中找到一个最小的&#xff0c;不断放入新的数组中。&#xff08;不使用数组的slice等方法是因为会使效率变得更慢&#xff09; let arr [3, 5, 6, 7, 1, 2, 4, 9, 8]function getMin(arr) {if (arr null || arr.length 0) retur…

Oracle VM(虚拟机)性能监控工具

Oracle VM是一个独立的虚拟化环境&#xff0c;由 Oracle 提供支持和设计&#xff0c;旨在为运行虚拟机提供轻量级、安全的基于服务器的平台。Oracle VM 能够在受支持的虚拟化环境中部署操作系统和应用软件&#xff0c;Oracle VM 将用户和管理员与底层虚拟化技术隔离开来&#x…

cmake编译faiss源码记录

文章目录 简介下载源码安装环境编译 简介 Faiss&#xff08;Facebook AI Similarity Search&#xff09;是一个由Facebook AI研发并开源的&#xff0c;用于大规模向量检索的库。其核心算法采用了聚类、压缩和量化等技术&#xff0c;以优化最近邻搜索的效率和准确性。Faiss提供…

ctfshow xxe web373-378

web373 libxml_disable_entity_loader(false)&#xff1a;这行代码用于启用实体加载器&#xff0c;允许加载外部实体。 $xmlfile file_get_contents(php://input)&#xff1a;从输入流中读取XML数据并存储在 $xmlfile 变量中。 $dom->loadXML($xmlfile, LIBXML_NOENT |…

异常信息泄露 应用程序错误泄露 原理以及修复方法

漏洞名称&#xff1a;未自定义统一错误页面导致信息泄露&#xff0c;抛出异常信息泄露&#xff0c;错误详情信息泄漏&#xff0c;AWVS漏洞名称如下&#xff1a; Application error message Error message on page ASP.NET error message 漏洞描述&#xff1a;攻击者可通过构造…

FebHost:意大利.IT域名一张意大利网络名片

.IT域名是意大利的国家顶级域名&#xff0c;对于意大利企业和个人而言,拥有一个属于自己的”.IT”域名无疑是件令人自豪的事。这个被誉为意大利互联网标志性代表的域名,不仅隐含着浓厚的意大利文化特色,还为使用者在当地市场的推广铺平了道路。 对于那些希望在意大利市场建立强…

微信开发者工具接入短剧播放器插件

接入短剧播放插线 申请添加插件基础接入app.jsonapp.jsplayerManager.js数据加密跳转到播放器页面运行出错示例小程序页面页面使用的方法小程序输入框绑定申请添加插件 添加插件:登录微信开发者平台 ——> 设置 ——> 第三方设置 ——> 插件管理 ——> 搜索“短剧…

基于SpringBoot + Vue实现的养老院管理系统设计与实现+毕业论文(12000字)+搭建视频

介绍 养老院管理系统是一款运用软件开发技术设计实现的应用系统&#xff0c;在信息处理上可以达到快速的目的&#xff0c;不管是针对数据添加&#xff0c;数据维护和统计&#xff0c;以及数据查询等处理要求&#xff0c;养老院管理系统都可以轻松应对。 系统包含登录、注册、…