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. python-中缀转换后缀并计算

    这个好像比较简单. 前缀规则好像还没有理清楚. # coding = utf-8 class Stack: def __init__(self): self.items = [] # 是否为空 def ...

  2. C#学习-析构函数

    析构函数用于在类销毁之前释放类实例所使用的托管和非托管资源. 对于C#应用程序所创建的大多数对象,可以依靠.NET Framework的垃圾回收器(GC)来隐式地执行内存管理任务. 但是,若创建封装了 ...

  3. 记录一次因代理Controller产生的404问题

    spring 3.2.4 为了给每一个controller配置一个拦截器链 import com.google.common.collect.Lists; import org.aopalliance ...

  4. noip宝藏

    题解: 我觉得状压比搜索不知道简单到哪里去了.. 为了练习搜索...想了一下这题的搜索.. 然后会发现想想就很容易想到dp.. 最后的搜索大概是这样的 我们会发现有一类搜索都是这样 你会重复(可能是指 ...

  5. npm淘宝镜像的设置和删除

    设置 npm config set registry https://registry.npm.taobao.org npm config set disturl https://npm.taobao ...

  6. Codeforces 965E Short Code 启发式合并 (看题解)

    Short Code 我的想法是建出字典树, 然后让后面节点最多的点优先向上移到不能移为止, 然后gg. 正确做法是对于当前的节点如果没有被占, 那么从它的子树中选出一个深度最大的点换到当前位置. 用 ...

  7. js判断上传图片文件大小,尺寸,格式

    /** * 文件宽高 * @param eventId id * @param w 宽度 * @param h 高度 * @param callback 回调函数这里判断图片像素的方法是异步的,所以需 ...

  8. mybatis中if test 可以使用== != null '' and or 和括号()

    <if test="pd.flag==1 or ((pd.flag==2 or pd.flag==3) and (pd.sfyj==2 or pd.sfyj==3)) or pd.fl ...

  9. Powershell极速教程-如何在三分钟内编写项目编译脚本

    分析及思路 来看一下项目目录结构 炒鸡正常的三板斧src+docs+tests.咦,怎么会多出一个build的文件夹呢,这就是我们今天要研究的目录.今天我会带着大家在五分钟之内编写一个极简的编译脚本. ...

  10. JavaScript 作用域的误区

    了解JavaScript的同学可能知道,JavaScript语言由于设计原因,导致语言本身存在很多先天性的不足,当然这并非设计者有意的,js语言最初是被设计来作为网页交互的脚本语言,依照现有的js语法 ...