文档章节

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

moki_oschina
 moki_oschina
发布于 04/10 16:51
字数 666
阅读 91
收藏 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
博文 190
码字总数 39623
作品 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/03/27
3.2K
6

没有更多内容

加载失败,请刷新页面

加载更多

MySQL 索引 explain索引分析优化

EXPLAIN是MySQL提供的工具,可用于模拟优化器执行SQL查询语句,从而知道MySQL是如何处理SQL语句的,包括表的读取顺序、数据读取操作的操作类型、可能使用的索引、实际使用的索引、表之间的引...

PeakFang-BOK
19分钟前
1
0
17-《深度拆解JVM》之即时编译(上)

一、问题引入 在第一篇中,我们简单了解过即时编译。这是一项用来提升应用程序运行效率的技术。通常而言,代码会先被 Java 虚拟机解释执行,之后反复执行的热点代码则会被即时编译成为机器码...

飞鱼说编程
19分钟前
1
0
OSChina 周二乱弹 —— 请上车吧

Osc乱弹歌单(2018)请戳(这里) 【今日歌曲】 @2amor :分享王菲的单曲《闷》 《闷》- 王菲 手机党少年们想听歌,请使劲儿戳(这里) @開源中國周杰倫 :昨天睡觉肚子疼,妈蛋,半夜爬起来...

小小编辑
今天
745
11
工作中如何做好技术积累

参考:https://tech.meituan.com/study_vs_work.html 看了这篇文章,觉得总结得非常好,因此摘抄了一些关键点,以便自己经常翻阅。 引言 在繁忙的工作中做好技术积累,构建个人核心竞争力. 在...

grace_233
今天
9
0
Mariadb二进制包安装,Apache安装

安装mariadb 下载二进制包并解压 [root@test-a src]# wget https://downloads.mariadb.com/MariaDB/mariadb-10.2.6/bintar-linux-glibc_214-x86_64/mariadb-10.2.6-linux-glibc_214-x86_64.t......

野雪球
今天
4
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部