• unique_lock 取代lock_quard
  • unique_lock 的第二个参数
    • std::adopt_lock
    • std::try_to_lock
    • std::defer_lock
  • unique_lock的成员函数
    • lock()
    • unlock()
    • try_to_lock()
    • release()
  • unique_lock所有权的传递

unique_lock 取代lock_guard

应用场景:两个线程A、B,其中A对队列添加元素,B移除元素。

unique_lock是个类模板,工作中,一般使用lock_gard(推荐使用),取代mutex的lock()和unlock()。unique_lock比lock_gard灵活许多,但是unique_lock效率差一点,并且内存占用多一点。

std::unique_lock<std::mutex> sbgard(mu_mutex);

unique_lock 的第二个参数

unique_lock比较灵活,主要是因为这个第二个参数。 lock_guard可以带第二个参数。

std::unique_lock<std::mutex> sbguard(my_mutex, std::adopt_lock);

  std::adopt_lock这个参数表示标记作用,unique_lock支持更多参数,表示互斥量已经被lock了

std::adopt_lock:表示这个互斥量已经被Lock了,必须把互斥量提前lock,否则会报异常。这个标记的效果:假设调用方线程已经拥有了互斥的所有权,也就是说已经lock成功了,通知lock_guard不需要在构造函数中Lock这个互斥量了。unique_lock也是同样的功能,就是不希望在unique_lock()的构造函数中再次lock了。

std::adopt_lock

用adopt_lock的前提条件是要先给互斥量加锁,然后在后面的语句中不会再次lock(),即后续的std::lock_guard中才能使用std::adopt_lock这个参数,然后unique_lock自动unlock。

std::unique_lock<std::mutex> sbguard(my_mutex, std::adopt_lock);

  如果另外一个线程A拿了锁之后,执行20s,然后这个线程B等待A释放锁。此时,A一直占用资源,B一直得不到资源,unique_lock如果一直拿不到锁,让它去先做别的事情,所以引入了try_to_lock。

std::try_to_lock

std::try_to_lcok会尝试用 mutex的lock()去锁定mutex,但是没有锁定成功,也会立即返回,并不会阻塞。用try_to_lock的前提是不能使用lock:

std::unique_lock<std::mutex> sbguard(my_mutex, std::try_to_lock);

  a)注意,不能先去try_to_lock,尝试加锁。此时就有成功或者失败,尝试拿锁成功或者尝试拿锁失败。

  b)如果拿到了锁,才能去操作共享数据(临界区),sbguard.owns_lock拿到锁,就不能操作共享数据,可以做一些别的事情。

  c)A拿到锁,sleep 20s,此时B拿不到锁,一直在等待。线程不需要一直等资源,通过sbguard.owns_lock的值进行判断。

std::defer_lock

前提:不能自己先lock,否者会出现异常。defer_lock的意思不需要给mutex加锁:初始化了没有加锁的mutex,没加锁的mutex,可以灵活地调用unique_lock的一些重要的成员函数。

std::unique_lock<std::mutex> sbguard(my_mutex, std::defer_lock);

 之后需要手动 lock,unlock在析构函数中自动执行了。

unique_lock的成员函数

a)lock(),加锁

b)unlock(),解锁

有lock就可以有unlock,不过在unique_lock中使用了锁,类的析构函数执行了解锁的操作。有的时候会出问题,但是实际上不稳定。有的时候可能临时需要处理一些其他事情。

lock()

//处理一些共享数据

unlock()

  也可以用unqiue_lock,编码变得更加灵活:

std::unique_lock<std::mutex> sbguard(mutex);

lock();

//处理一些共享数据

unlock();

//处理一些非共享数据

lock();

////

////

  此时unlock不必手工unlock,此时的unlock在unique_lock的析构函数中执行。

try_lock()

尝试给互斥量加锁,如果拿不到锁,则返回false,如果拿到了锁,返回true,函数不阻塞。

if(sbguard.try_lock()==true)
{
//拿到锁了
访问共享数据
}else
{
//没拿到锁 }

release()

返回它所管理的mutex对象指针,并释放所有权,也就是说这个unique_lock和mutex不再有关系,严格区分unlock()和release()的区别。release()把绑在一起的东西解开了(解开关系),unlock()是解开锁头。

如果原来mutex对象处于加锁状态,需要接管过来并负责解锁。

std::unique_lock<std::mutex> sbguard(my_mutex);
std::mutex *ptx = sbguard.release();
//此时sbguard和my_mutex的关系解除了,现在就有责任自己解锁my_mutex
//如果自己不解锁,那么就卡住了

解锁语法:自己负责my_mutex的解锁。

ptx->nulock();

 release()返回的是原始的mutex指针。

锁头锁住的代码的多少成为粒度,粒度一般用粗细来描述;

a)锁住代码少,粒度细,执行效率高。

b)锁住代码多,粒度粗,执行效率低。

要学会尽量选择合适粒度的代码进行保护。

unique_lock所有权的传递

unique_lock需要和mutex绑定到一起才是一个完整的unique_lock,应该是unique_lock需要管理一个mutex指针才能起作用。

所有权:指定unique_lock拥有mutex的所有权,unique_lock可以把所有用的所有权,可以转移给其他的unique_lock对象,所有权转移,mutex可以转移,但是不能复制

可以使用std::move(mutex)

std::unique_lock<std::mutex>  sbguard1(mutex);
std::unique_lock<std::mutex> sbguard2(std::move(mutex));

 此时sbguard1为空,sbguard2接管了原来sbguard1和mutex的关系,其实就是新的unique_lock()指向了原来的mutex。

参考文献

https://blog.csdn.net/guanguanboy/article/details/100514731

C++并发与多线程学习笔记--unique_lock详解的更多相关文章

  1. C++并发与多线程学习笔记--参数传递详解

    传递临时对象 陷阱 总结 临时对象作为线程参数 线程id的概念 临时对象构造时的抓捕 成员函数指针做线程函数 传递临时对象作为线程参数 创建的工作线程不止一个,线程根据编号来确定工作内容.每个线程都需 ...

  2. 多线程05:unique_lock详解

    unique_lock详解 一.unique_lock取代lock_guard unique_lock是个类模板,实际应用中,一般lock_guard(推荐使用):lock_guard取代了mutex ...

  3. C++并发与多线程学习笔记--atomic

    std::atomic std::async std::atomic 一般atomic原子操作,针对++,--,+=,^=是支持的,其他结果可能不支持. 注意 std::atomic<int&g ...

  4. Angular6 学习笔记——组件详解之组件通讯

    angular6.x系列的学习笔记记录,仍在不断完善中,学习地址: https://www.angular.cn/guide/template-syntax http://www.ngfans.net ...

  5. Angular6 学习笔记——组件详解之模板语法

    angular6.x系列的学习笔记记录,仍在不断完善中,学习地址: https://www.angular.cn/guide/template-syntax http://www.ngfans.net ...

  6. Angular6 学习笔记——路由详解

    angular6.x系列的学习笔记记录,仍在不断完善中,学习地址: https://www.angular.cn/guide/template-syntax http://www.ngfans.net ...

  7. JavaScript学习笔记-实例详解-类(二)

    实例详解-类(二)   //===给Object.prototype添加只读\不可枚举\不可配置的属性objectId(function(){ Object.defineProperty(Object ...

  8. JavaScript学习笔记-实例详解-类(一)

    实例详解-类(一): //每个javascript函数(除了bind())都自动拥有一个prototype对象// 在未添加属性或重写prototype对象之前,它只包含唯一一个不可枚举属性const ...

  9. Android学习笔记-Dialog详解

    1.对话框的使用 1.1AlertDialog的显示 简单对话框以及监听的设置:重点掌握三个按钮(也就是三上单词): PositiveButton(确认按钮);NeutralButton(忽略按钮) ...

随机推荐

  1. yarn & uninstall global & yarn global remove

    yarn uninstall global yarn global remove https://yarnpkg.com/lang/en/docs/cli/remove/ https://yarnpk ...

  2. nodejs stream 创建读写流

    const fs = require("fs"); const { Writable, Readable, Duplex, Transform } = require(" ...

  3. c++ 动态设置函数

    #include <iostream> #include <Windows.h> #include <TlHelp32.h> using namespace std ...

  4. react UI 框架对比

    传送门  https://blog.csdn.net/qiqingjin/article/details/79219206 点击

  5. Masterboxan INC :个股出现疯涨,投资者需警惕股市泡沫

    随着标普500指数自去年三月以来的暴涨,引发了很多亏损企业股价飙升,同时许多场外投资者盲目跟风,加剧了个股的疯涨.对于此现象,美国万事达资产管理有限公司不得不多次发文提醒投资者:个股出现疯涨,投资者需 ...

  6. NGK公链:在规则明确的环境下运行超级节点机制

    首先要跟大家明确的一点是,21个超级节点是投票选举出来的,并不是系统在创立之初就已经确定好了的.那么相信大家也一定很好奇,这21个超级节点是通过什么方式产生? NGK.IO对分布式超级节点使用了一个自 ...

  7. ⑧SpringCloud 实战:引入 Actuator监控+整合监控页面

    Actuator是什么? Spring Boot Actuator 模块提供了生产级别的功能,比如健康检查,审计,指标收集,HTTP 跟踪等,帮助我们监控和管理Spring Boot 应用.这个模块是 ...

  8. DHCP (Dynamic Host Configuration Protocol )协议的探讨与分析

    DHCP (Dynamic Host Configuration Protocol )协议的探讨与分析 问题背景 最近在工作中遇到了连接外网的交换机在IPv6地址条件下从运营商自动获取的DNS地址与本 ...

  9. webpack理解

    打包工具 可以将多个静态文件打包成一个静态文件例如将1.js.2.js.3.css打包成h.js一个静态文件 这样做的好处是:可以减少页面的请求次数 以往是请求多个静态页面,使用webpack后会减少 ...

  10. HDFS中的NameNode名节点——FSimage

    HDFS缓冲区 Fsimage 文件映射,Edits文件操作记录. 与ES的缓冲区不同,ES是维护数据的变更,而HDFS缓冲区是用于名结点维护文件系统元数据(目录树)的机制. 在HDFS集群中,Nam ...