C++11并发学习之三:线程同步(转载)
C++11并发学习之三:线程同步
1.<mutex> 头文件介绍
Mutex又称互斥量,C++ 11中与 Mutex 相关的类(包括锁类型)和函数都声明在 <mutex> 头文件中,所以如果你需要使用 std::mutex,就必须包含 <mutex> 头文件。
(1)Mutex系列类(四种)
std::mutex,最基本的 Mutex 类。
std::recursive_mutex,递归 Mutex 类。
std::time_mutex,定时 Mutex 类。
std::recursive_timed_mutex,定时递归 Mutex 类。
(2)Lock系列类(两种)
std::lock_guard,与 Mutex RAII 相关,方便线程对互斥量上锁。
std::unique_lock,与 Mutex RAII 相关,方便线程对互斥量上锁,但提供了更好的上锁和解锁控制。
(3)其他类型(结构体)
std::adopt_lock_t——它的常量对象定义为constexpr adopt_lock_t adopt_lock {};// constexpr 是 C++11 中的新关键字)
std::defer_lock_t——它的常量对象定义为constexpr defer_lock_t defer_lock {};// constexpr 是 C++11 中的新关键字)
std::try_to_lock_t——它的常量对象定义为constexpr try_to_lock_t try_to_lock {};// constexpr 是 C++11 中的新关键字)
(4)函数
std::try_lock,尝试同时对多个互斥量上锁。
std::lock,可以同时对多个互斥量上锁。
std::call_once,如果多个线程需要同时调用某个函数,call_once 可以保证多个线程对该函数只调用一次。
2.常用类型举例
(1)std::mutex类
☆构造函数,std::mutex不允许拷贝构造,也不允许 move 拷贝,最初产生的 mutex 对象是处于 unlocked 状态的。
☆lock(),调用线程将锁住该互斥量。线程调用该函数会发生下面 3 种情况:①如果该互斥量当前没有被锁住,则调用线程将该互斥量锁住,直到调用 unlock之前,该线程一直拥有该锁。②如果当前互斥量被其他线程锁住,则当前的调用线程被阻塞住。③如果当前互斥量被当前调用线程锁住,则会产生死锁(deadlock)。
☆unlock(), 解锁,释放对互斥量的所有权。
☆try_lock(),尝试锁住互斥量,如果互斥量被其他线程占有,则当前线程也不会被阻塞。线程调用该函数也会出现下面 3 种情况:① 如果该互斥量当前没有被锁住,则该线程锁住互斥量,直到该线程调用 unlock 释放互斥量。②如果当前互斥量被其他线程锁住,则当前调用线程返回 false,而并不会被阻塞掉。③如果当前互斥量被当前调用线程锁住,则会产生死锁(deadlock)。
不论是lock()还是try_lock()都需要和unlock()配套使用,下面举例说明lock()和try_lock()的区别。
- #include <thread>
- #include <iostream>
- #include <string>
- #include <chrono>
- #include <assert.h>
- #include <mutex>
- int counter=0;
- std::mutex mtx;
- void func()
- {
- for (int i=0; i<10000; ++i)
- {
- mtx.lock();
- ++counter;
- mtx.unlock();
- }
- }
- int main()
- {
- std::thread workerThreads[10];
- for (int i=0; i<10; ++i)
- {
- workerThreads[i] = std::thread(func);
- }
- for (auto& workerThread : workerThreads)
- {
- workerThread.join();
- }
- std::cout << counter << " successful increases of the counter"<<std::endl;
- return 0;
- }
由于lock()的阻塞特性,所以每个线程都统计了10000次,一共是10*10000=100000次。
- #include <thread>
- #include <iostream>
- #include <string>
- #include <chrono>
- #include <assert.h>
- #include <mutex>
- int counter=0;
- std::mutex mtx;
- void func()
- {
- for (int i=0; i<10000; ++i)
- {
- if (mtx.try_lock())
- {
- ++counter;
- mtx.unlock();
- }
- }
- }
- int main()
- {
- std::thread workerThreads[10];
- for (int i=0; i<10; ++i)
- {
- workerThreads[i] = std::thread(func);
- }
- for (auto& workerThread : workerThreads)
- {
- workerThread.join();
- }
- std::cout << counter << " successful increases of the counter"<<std::endl;
- return 0;
- }
由于try_lock()的非阻塞特性,如果当前互斥量被其他线程锁住,则当前try_lock()返回 false,此时counter并不会增加1。所以这十个线程的统计结果具有随机性,下次运行程序时,统计值不一定是16191。
(2).std::lock_guard和std::unique_lock类
std::lock_guard使用起来比较简单,除了构造函数外没有其他成员函数。
std::unique_lock除了lock_guard的功能外,提供了更多的成员函数,相对来说更灵活一些。这些成员函数包括lock,try_lock,try_lock_for,try_lock_until、unlock等。
std::unique_lock::lock——用它所管理的Mutex对象的 lock 函数。
std::unique_lock::try_lock——用它所管理的Mutex对象的 try_lock函数。
std::unique_lock::unlock——用它所管理的Mutex对象的 unlock函数。
这两个类相比使用std::mutex的优势在于不用配对使用,无需担心忘记调用unlock而导致的程序死锁。
- #include <thread>
- #include <iostream>
- #include <string>
- #include <chrono>
- #include <assert.h>
- #include <mutex>
- int counter=0;
- std::mutex mtx;
- void func()
- {
- for (int i=0; i<10000; ++i)
- {
- //将std::lock_guard替换成std::unique_lock,效果是一样的
- std::lock_guard<std::mutex> lck (mtx);
- ++counter;
- }
- }
- int main()
- {
- std::thread workerThreads[10];
- for (int i=0; i<10; ++i)
- {
- workerThreads[i] = std::thread(func);
- }
- for (auto& workerThread : workerThreads)
- {
- workerThread.join();
- }
- std::cout << counter << " successful increases of the counter"<<std::endl;
- return 0;
- }
std::uniqure_lock构造函数的第二个参数可以是std::defer_lock,std::try_to_lock或std::adopt_lock
- #include <thread>
- #include <iostream>
- #include <string>
- #include <chrono>
- #include <assert.h>
- #include <mutex>
- int counter=0;
- std::mutex mtx;
- void func()
- {
- for (int i=0; i<10000; ++i)
- {
- mtx.lock();
- //注意此时Tag参数为std::adopt_lock表明当前线程已经获得了锁,
- //此后mtx对象的解锁操作交由unique_lock对象lck来管理,在lck的生命周期结束之后,
- //mtx对象会自动解锁。
- std::unique_lock<std::mutex> lck(mtx,std::adopt_lock);
- ++counter;
- }
- }
- int main()
- {
- std::thread workerThreads[10];
- for (int i=0; i<10; ++i)
- {
- workerThreads[i] = std::thread(func);
- }
- for (auto& workerThread : workerThreads)
- {
- workerThread.join();
- }
- std::cout << counter << " successful increases of the counter"<<std::endl;
- return 0;
- }
- #include <chrono>
- #include <assert.h>
- #include <mutex>
- int counter=0;
- std::mutex mtx;
- void func()
- {
- for (int i=0; i<10000; ++i)
- {
- //注意此时Tag参数为std::defer_lock表明当前线程没有获得了锁,
- //需要通过lck的lock和unlock来加锁和解锁,
- std::unique_lock<std::mutex> lck(mtx,std::defer_lock);
- lck.lock();
- ++counter;
- lck.unlock();
- }
- }
- int main()
- {
- std::thread workerThreads[10];
- for (int i=0; i<10; ++i)
- {
- workerThreads[i] = std::thread(func);
- }
- for (auto& workerThread : workerThreads)
- {
- workerThread.join();
- }
- std::cout << counter << " successful increases of the counter"<<std::endl;
- return 0;
- }
参考链接:http://www.cnblogs.com/haippy/p/3346477.html
C++11并发学习之三:线程同步(转载)的更多相关文章
- AspectJ基础学习之三HelloWorld(转载)
AspectJ基础学习之三HelloWorld(转载) 一.创建项目 我们将project命名为:aspectjDemo.然后我们新建2个package:com.aspectj.demo.aspect ...
- Python并发编程-进程 线程 同步锁 线程死锁和递归锁
进程是最小的资源单位,线程是最小的执行单位 一.进程 进程:就是一个程序在一个数据集上的一次动态执行过程. 进程由三部分组成: 1.程序:我们编写的程序用来描述进程要完成哪些功能以及如何完成 2.数据 ...
- java SE学习之线程同步(详细介绍)
java程序中可以允许存在多个线程,但在处理多线程问题时,必须注意这样一个问题: 当两个或多个线程同时访问同一个变量,并且一些线程需要修改这个变量时,那么这个 ...
- Java提高班(三)并发中的线程同步与锁
乐观锁.悲观锁.公平锁.自旋锁.偏向锁.轻量级锁.重量级锁.锁膨胀...难理解?不存的!来,话不多说,带你飙车. 上一篇介绍了线程池的使用,在享受线程池带给我们的性能优势之外,似乎也带来了另一个问题: ...
- C++并发编成 03 线程同步
这一节主要讲讲线程同步的方式,C++ 11中提供了丰富的线程同步元语,如condition_variable,futrue,std::packaged_task<>,std::promis ...
- java并发编程:线程同步和锁
一.锁的原理 java中每个对象都有一个内置锁.当程序运行到非静态的synchronized同步方法上时,自动获得与正在执行代码类的当前实例(this)有关的锁.获得一个对象的锁也称为获取锁,当程序运 ...
- Java多线程学习总结--线程同步(2)
线程同步是为了让多个线程在共享数据时,保持数据的一致性.举个例子,有两个人同时取钱,假设用户账户余额是1000,第一个用户取钱800,在第一个用户取钱的同时,第二个用户取钱600.银行规定,用户不允许 ...
- java并发编程基础——线程同步
线程同步 一.线程安全问题 如果你的代码所在的进程中有多个线程在同时运行,而这些线程可能会同时运行这段代码.如果每次运行结果和单线程运行的结果是一样的,而且其他的变量的值也和预期的是一样的,就是线程安 ...
- APUE学习笔记——11 线程同步、互斥锁、自旋锁、条件变量
线程同步 同属于一个进程的不同线程是共享内存的,因而在执行过程中需要考虑数据的一致性. 假设:进程有一变量i=0,线程A执行i++,线程B执行i++,那么最终i的取值是多少呢?似乎一定 ...
随机推荐
- Codeforces 1037F. Maximum Reduction
总感觉我这种做法会T,一直没写,看了其他人的题解也是这样,,,就果断写了,,可能数据不太深,或者玄学复杂度 题意即求xk-1长度的所有区间的最大值的和,对每一个i(数组下边),他对答案的贡献数量就是在 ...
- Codeforces 1029 E. Tree with Small Distances(树上dp)
题目直通车:http://codeforces.com/problemset/problem/1029/E 思路大意:在树上做dp,依次更新ar数组,ar[i]表示以i为根节点的子树对答案的最小贡献值 ...
- 数学【P2524】 Uim的情人节礼物·其之弐 (康托展开)
因为某人@ZAGER挖坑让我讲一下康托展开,所以发现了这个题,顺便说一下康托展开是个什么东西 题目概括 给定n与一个数列,要求求出给定数列在n的全排列中的排名(按照字典序从小到大排列) 康托展开 先放 ...
- Oracle 查询每天执行慢的SQL
本文转载自http://blog.itpub.net/28602568/viewspace-1364844/ 前言: 工作中的您是否有 想对每天慢的sql进行查询.汇总或者行优化等情况,如下SQL希 ...
- [BZOJ5289][HNOI2018]排列(拓扑排序+pb_ds)
首先确定将所有a[i]向i连边之后会形成一张图,图上每条有向边i->j表示i要在j之前选. 图上的每个拓扑序都对应一种方案(如果有环显然无解),经过一系列推导可以发现贪心策略与合并的块的大小和w ...
- 设计模式之原型模式(php实现)
github地址:https://github.com/ZQCard/design_pattern1.先了解什么是浅拷贝与深拷贝 //深拷贝:赋值时值完全复制,完全的copy,对其中一个作出改变,不会 ...
- 超级惊艳 10款HTML5动画特效推荐[转]
ylbtech_html5_demo 今天我们要来推荐 10 款超级惊艳的 HTML5 动画特效,有一些是基于 CSS3 和 jQuery 的,比较实用,特别是前几个 HTML5 动画,简直酷毙了,现 ...
- 彻底解决DZ大附件上传问题
个. 注意:很多人遇到修改php.ini后重应WEB服务后仍然不能生效.这种情况应该先确认一下所改的php.ini是不是当前PHP所使用的.您可以在WEB目录下建立一个php文件,内容很简单就一句话& ...
- python数据类型学习心得
python中的数据类型 数字:整型,长整形,布尔型,浮点型,复数 整型:普通的整数,在32位的操作系统中范围在-2的-32次方到2的32次方-1,64位的操作系统则为-2的64次方到2的64次方-1 ...
- Xml解析(Dom解析xml)
xml四种解析方式: DOM 平台无关的官方解析方式 优点:形成了树结构,直观好理解,代码更易编写 解析过程中树结构保留在内存中,方便修改 缺点:当xml文件较大时,对内存耗费比较大,容易影响解析性能 ...