C++多线程编程中通常会对共享的数据进行写保护,以防止多线程在对共享数据成员进行读写时造成资源争抢导致程序出现未定义的行为。通常的做法是在修改共享数据成员的时候进行加锁--mutex。在使用锁的时候通常是在对共享数据进行修改之前进行lock操作,在写完之后再进行unlock操作,进场会出现由于疏忽导致由于lock之后在离开共享成员操作区域时忘记unlock,导致死锁。

针对以上的问题,C++11中引入了std::unique_lock与std::lock_guard两种数据结构。通过对lock和unlock进行一次薄的封装,实现自动unlock的功能。

  1. std::mutex mut;
  2. void insert_data()
  3. {
  4. std::lock_guard<std::mutex> lk(mut);
  5. queue.push_back(data);
  6. }
  7. void process_data()
  8. {
  9. std::unqiue_lock<std::mutex> lk(mut);
  10. queue.pop();
  11. }

std::unique_lock 与std::lock_guard都能实现自动加锁与解锁功能,但是std::unique_lock要比std::lock_guard更灵活,但是更灵活的代价是占用空间相对更大一点且相对更慢一点。

通过实现一个线程安全的队列来说明两者之间的差别。

  template <typename T>

  1. class ThreadSafeQueue{
  2. public:
  3. void Insert(T value);
  4. void Popup(T &value);
  5. bool Empety();
  6. private:
  7. mutable std::mutex mut_;
  8. std::queue<T> que_;
  9. std::condition_variable cond_;
  10. };

  template <typename T>

  1. void ThreadSafeQueue::Insert(T value){
  2. std::lock_guard<std::mutex> lk(mut_);
  3. que_.push_back(value);
  4. cond_.notify_one();
  5. }
  6. template <typename T>
  7. void ThreadSafeQueue::Popup(T &value){
  8. std::unique_lock<std::mutex> lk(mut_);
  9. cond_.wait(lk, [this]{return !que_.empety();});
  10. value = que_.front();
  11. que_.pop();
  12. }
  13. template <typename T>
  14. bool ThreadSafeQueue::Empty() const{
  15. std::lock_guard<std::mutex> lk(mut_);
  16. return que_.empty();
  17. }

上面代码只实现了关键的几个函数,并使用了C++11新引入的condition_variable条件变量。从Popup与Inert两个函数看std::unique_lock相对std::lock_guard更灵活的地方在于在等待中的线程如果在等待期间需要解锁mutex,并在之后重新将其锁定。而std::lock_guard却不具备这样的功能。

上面代码中

可能会比较难以理解,

  [this]{return !Empety();}

是C++11新引入的功能,lambda表达式,是一种匿名函数。方括号内表示捕获变量。当lambda表达式返回true时(即queue不为空),wait函数会锁定mutex。当lambda表达式返回false时,wait函数会解锁mutex同时会将当前线程置于阻塞或等待状态。

还存在另一种读写锁,但是并没有引入C++11,但是boost库提供了对应的实现。读写锁主要适合在于共享数据更新频率较低,但是读取共享数据频率较高的场合。

std::lock_guard/std::unique_lock的更多相关文章

  1. C++ folly库解读(三)Synchronized —— 比std::lock_guard/std::unique_lock更易用、功能更强大的同步机制

    目录 传统同步方案的缺点 folly/Synchronized.h 简单使用 Synchronized的模板参数 withLock()/withRLock()/withWLock() -- 更易用的加 ...

  2. 基于std::mutex std::lock_guard std::condition_variable 和std::async实现的简单同步队列

    C++多线程编程中通常会对共享的数据进行写保护,以防止多线程在对共享数据成员进行读写时造成资源争抢导致程序出现未定义的行为.通常的做法是在修改共享数据成员的时候进行加锁--mutex.在使用锁的时候通 ...

  3. std::unique_lock<std::mutex> or std::lock_guard<std::mutex> C++11 区别

    http://stackoverflow.com/questions/20516773/stdunique-lockstdmutex-or-stdlock-guardstdmutex The diff ...

  4. C++ 11 多线程下std::unique_lock与std::lock_guard的区别和用法

    这里主要介绍std::unique_lock与std::lock_guard的区别用法 先说简单的 一.std::lock_guard的用法 std::lock_guard其实就是简单的RAII封装, ...

  5. std::lock_guard和std::unique_lock

    std::unique_lock也可以提供自动加锁.解锁功能,比std::lock_guard更加灵活 https://www.cnblogs.com/xudong-bupt/p/9194394.ht ...

  6. C++ 并发编程,std::unique_lock与std::lock_guard区别示例

    背景 平时看代码时,也会使用到std::lock_guard,但是std::unique_lock用的比较少.在看并发编程,这里总结一下.方便后续使用. std::unique_lock也可以提供自动 ...

  7. C++11 std::unique_lock与std::lock_guard区别及多线程应用实例

    C++多线程编程中通常会对共享的数据进行写保护,以防止多线程在对共享数据成员进行读写时造成资源争抢导致程序出现未定义的行为.通常的做法是在修改共享数据成员的时候进行加锁--mutex.在使用锁的时候通 ...

  8. std::unique_lock与std::lock_guard分析

    背景 C++多线程编程中通常会对共享的数据进行写保护,以防止多线程在对共享数据成员进行读写时造成资源争抢,导致程序出现未定义或异常行为.通常的做法是在修改共享数据成员时进行加锁(mutex).在使用锁 ...

  9. std::unique_lock与std::lock_guard区别示例

    std::lock_guard std::lock_guard<std::mutex> lk(frame_mutex); std::unique_lock<std::mutex> ...

随机推荐

  1. 无法创建链接服务器 "ORCL" 的 OLE DB 访问接口 "OraOLEDB.Oracle" 的实例 (错误:7302)

    原文:https://www.cnblogs.com/tiger2soft/p/6954308.html 在sqlserver中创建oracle的链接服务器时,提示此错误. 按照网上的方案,先后使用了 ...

  2. signal() 和 sigaction()

    [摘自<Linux/Unix系统编程手册>] Unix系统提供了两种方式来改变信号处置:signal() 和 sigaction(). signal() 的行为在不同Unix实现间存在差异 ...

  3. .net core2.1 - ef core数据库迁移,初始化种子数据

    起因:早上偶然看见一篇文章说是ef core(2.x)使用种子数据,主表子表迁移时候,正常情况下说是无法迁移成功,索性就试试,结果是和ef6的一样,没感觉有什么大的区别.一切OK,见下面内容. 1.首 ...

  4. mysql排序(四)

    MySQL 排序 我们知道从 MySQL 表中使用 SQL SELECT 语句来读取数据. 如果我们需要对读取的数据进行排序,我们就可以使用 MySQL 的 ORDER BY 子句来设定你想按哪个字段 ...

  5. 【转】git shell 命令大全

    http://www.cnblogs.com/bugs/p/3384339.html 常用命令 git branch 查看本地所有分支 git status 查看当前状态 git commit 提交 ...

  6. 同构体字符串(如果 s 中的字符可以被替换得到 t ,那么这两个字符串是同构的。 所有出现的字符都必须用另一个字符替换,同时保留字符的顺序。两个字符不能映射到同一个字符上,但字符可以映射自己本身。)

    示例 1: 输入: s = "egg", t = "add" 输出: true 示例 2: 输入: s = "foo", t = " ...

  7. 003 使用SpringMVC开发restful API--查询用户

    一:介绍说明 1.介绍 2.restful api的成熟度 二:编写Restful API的测试用例 1.引入spring的测试框架 在effective pom中查找 2.新建测试包,测试类 3.测 ...

  8. quratz启动流程

    SchedulerFactory在创建quartzScheduler的过程中,将会读取配置参数,初始化各个组件. 1.启动流程图 2.ThreadPool 一般是使用SimpleThreadPool, ...

  9. jQuery获得页面绝对和相对的位置

    获得某一元素绝对x,y位置,可以用offset方法 var X = $('#DivID').offset().top; var y=$("#divid").offset().lef ...

  10. SVM:随机产生100个点,建立模型,找出超平面方程——Jaosn niu

    import numpy as np import pylab as pl from sklearn import svm # we create 40 separable points #np.ra ...