文档章节

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

moki_oschina
 moki_oschina
发布于 2018/04/10 16:51
字数 666
阅读 105
收藏 0

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

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

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

std::mutex mut;
 
void insert_data()
{
    std::lock_guard<std::mutex> lk(mut);
    queue.push_back(data);
}
 
void process_data()
{
    std::unqiue_lock<std::mutex> lk(mut);
    queue.pop();
}

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

 

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

template <typename t="">
class ThreadSafeQueue{
public:
         void Insert(T value);
         void Popup(T &value);
         bool Empety();
 
private:
       mutable std::mutex mut_;
       std::queue<t> que_;
       std::condition_variable cond_;
};


template <typename t="">
void ThreadSafeQueue::Insert(T value){
    std::lock_guard<std::mutex> lk(mut_);
    que_.push_back(value);
    cond_.notify_one();
}
 
 
template <typename t="">
void ThreadSafeQueue::Popup(T &value){
    std::unique_lock<std::mutex> lk(mut_);
    cond_.wait(lk, [this]{return !que_.empety();});
    value = que_.front();
    que_.pop();
}
 
 
template <typename t="">
bool ThreadSafeQueue::Empty() const{
    std::lock_guard<std::mutex> lk(mut_);
    return que_.empty();
}

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

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

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

 

 

 

 

 

 

 

 

本文转载自:https://www.2cto.com/kf/201706/649733.html

共有 人打赏支持
moki_oschina
粉丝 25
博文 202
码字总数 44864
作品 0
成都
程序员
私信 提问
C++11中std::lock_guard的使用

互斥类的最重要成员函数是lock()和unlock()。在进入临界区时,执行lock()加锁操作,如果这时已经被其它线程锁住,则当前线程在此排队等待。退出临界区时,执行unlock()解锁操作。更好的办法是...

fengbingchun
2017/11/27
0
0
C++11 多线程 Mutex篇 (续)

Mutex篇续 上一篇传送门 std::uniquelock::trylock_until 尝试调用uniquelock所管理的对象(注:该对象也必须支持trylockuntil)的trylockuntil(abstime)给所管理的互斥量上锁. (注:trylockun...

SHIHUAMarryMe
2016/03/19
108
0
C++11: Mutex和Lock

Mutex全名mutual exclusion(互斥体),是一个可加锁对象(lockable object),用来协助采取独占排他方式控制对资源的并发访问.这里的资源可能是个object,也可能是多个object的组合。为了获得独占式...

SHIHUAMarryMe
2016/03/18
246
0
C++11 并发编程教程 - Part 3 : 锁的进阶与条件变量

上一篇文章中我们学习了如何使用互斥量来解决一些线程同步问题。这一讲我们将进一步讨论互斥量的话题,并向大家介绍 C++11 并发库中的另一种同步机制 —— 条件变量。 递归锁 考虑下面这个简...

天下杰论
2013/12/29
0
0
C++11 并发教程第二部分:保护共享数据

在上一篇文章“C++11 并发 —— 第一部分:启动线程”中我们介绍了如何在C++11中编写多线程程序,这些在线程中执行的代码都是独立的,但在实际应用中,我们经常会需要线程去访问一些共享的数...

彭博
2012/11/27
419
0

没有更多内容

加载失败,请刷新页面

加载更多

Python如何开发桌面应用程序?Python基础教程,第十三讲,图形界面

当使用桌面应用程序的时候,有没有那么一瞬间,想学习一下桌面应用程序开发?行业内专业的桌面应用程序开发一般是C++,C#来做,Java开发的也有,但是比较少。本节课会介绍Python的GUI(图形用...

程序员补给栈
51分钟前
3
0
kafka在的使用

一、基本概念 介绍 Kafka是一个分布式的、可分区的、可复制的消息系统。它提供了普通消息系统的功能,但具有自己独特的设计。 这个独特的设计是什么样的呢? 首先让我们看几个基本的消息系统...

狼王黄师傅
58分钟前
1
0
Android JNI总结

0x01 JNI介绍 JNI是Java Native Interface的缩写,JNI不是Android专有的东西,它是从Java继承而来,但是在Android中,JNI的作用和重要性大大增强。 JNI在Android中起着连接Java和C/C++层的作...

天王盖地虎626
昨天
1
0
大数据教程(11.8)Hive1.2.2简介&初体验

上一篇文章分析了Hive1.2.2的安装,本节博主将分享Hive的体验&Hive服务端和客户端的使用方法。 一、Hive与hadoop直接的关系 Hive利用HDFS存储数据,利用MapReduce查询数据。 二、Hive与传统数...

em_aaron
昨天
3
0
跟我学Spring Cloud(Finchley版)-15-Hystrix监控详解

Hystrix提供了监控Hystrix Command的能力,本节来详细探讨。 监控端点与数据 应用整合Hystrix,同时应用包含spring-boot-starter-actuator 依赖,就会存在一个/actuator/hystrix.stream 端点...

周立_ITMuch
昨天
7
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部