C++11 多线程相关的头文件
- C++ 新标准中引入了四个头文件来支持多线程编程,他们分别是 < atomic>, < thread>, < condition_variable> 和< future>.
- < atomic>:该头文件主要声明了两个类,std::atomic和std::atomic_flag,另外还声明了一套C分格的原子类型和与C兼容的原操作的函数.
- < thread>:该头文件主要声明了std::thread类,另外std::this_thread命名空间也在该头文件中.
- < mutex>:该头文件主要申明了与互斥量(mutex)相关的类,包括std::mutex系列类,std::lock_guard,std::unique_lock,以及其他类型和函数.
- :该头文件主要声明了与条件变量相关的类,包括std::condition_variable和std::condition_variable_any.
- < future>:该头文件主要申明了std::promise,std::package_task两个Provider类,以及std::future和std::share_future两个Future类,另外还有一些与之相关的类型和函数,std::async()函数就声明在此文件中.
std::thread构造函数
- default thread() noexcept; //noexcept不会抛出异常,默认构造函数,创建一个空的thread执行对象.
- initialization template
move赋值操作
- move(1) thread& operator=(thread& rhs) noexcept;
- copy delete thread operator(const thread &)=delete;
(1)move 赋值操作,如果当前对象不可joinable,需要传递一个右值引用(rhs)给move赋值操作,如果当前对象可被joinable,则terminate()报错.
(2)拷贝赋值操作被禁用,thread 对象不可被拷贝。
线程调用到的函数在一个类中,那必须将该函数申明为静态函数,因为静态成员函数属于静态全局区,线程可以共享这个区域,故可以各自调用.
< mutex>头文件介绍
Mutex系列类(4种)
- std::mutex,最基本的Mutex类.
- std::recursive_mutex,递归Mutex类.
- std::time_mutex,定时Mutex类.
- std::recursive_timed_mutex,定时递归Mutex类.
Lock类(2种)
- std::lock_guard,与Mutex RAII相关,方便线程对互斥量上锁.
- std::unique_lock,与Mutex RAII相关,方便线程对互斥量上锁,但提供了更好的上锁和解锁控制.
其他类型
- std::once_flag
- std::adopt_lock_t
- std::defer_lock_t
- std::try_to_lock_t
函数
- std::try_lock,尝试同时对多个互斥量上锁.
- std::lock,可以同时对多个互斥量上锁.
- std::call_once,如果多个线程需要同时调用某个函数,call_once可以保证多个线程对该函数只调用一次.
std::mutex的成员函数
- 构造函数,std::mutex不允许拷贝构造,也不允许move拷贝,最初产生的mutex对象是处于unlockeed状态的.
- lock(),调用线程将锁住该互斥量,线程调用该函数会发生下面三种情况:(1)如果该互斥量当前没有被锁住,则调用线程将该互斥量锁住,直到调用unlock之前,该线程一直拥有该锁,(2)如果当前的互斥量被其他线程锁住,则当前的调用线程被阻塞.(3)如果当前互斥量被调用线程锁住,则会产生死锁.
- unlock(),解锁,释放对互斥量的所有权.
- try_lock(),尝试锁住互斥量如果互斥量被其他线程占有,则当前线程也不会被阻塞。线程调用该函数也会出现下面 3 种情况(1). 如果当前互斥量没有被其他线程占有,则该线程锁住互斥量,直到该线程调用 unlock 释放互斥量。(2). 如果当前互斥量被其他线程锁住,则当前调用线程返回 false,而并不会被阻塞掉。(3).如果当前互斥量被当前调用线程锁住,则会产生死锁(deadlock)。
几个与锁类型相关的Tag类,分别如下:
- std::adopt_lock_t,一个空的标记类,定义如下:struct adopt_lock_t{};该类型的常量对象adopt_lock(adopt_lock是一个常量对象,定义如下:constexpr adopt_lock_t adopt_lock{};通常作为参数传给unique_lock或lock_guard的构造函数.
- std::defer_lock_t,一个空的标记类,定义如下:struct defer_lock_t{}; 该类型的常量对象defer_lock (defer_lock 是一个常量对象,定义如下: constexpr defer_lock_t defer_lock{}; 通常作为参数传给unique_lock或lock_guard的构造函数.
- std::try_to_lock_t,一个空的标记类,定义如下: struct try_to_lock_t {}; 该类型常量对象try_to_lock(try_to_lock是一个常量对象,定义如下:constexpr try_to_lock_t try_to_lock{},通常作为参数传给unique_lock或lock_guard的构造函数.
std::lock_guard介绍
std::lock_gurad 是 C++11 中定义的模板类。定义如下:
template < class Mutex> class lock_guard;
lock_guard对象通常用于管理某个锁(Lock)对象,在某个lock_guard对象的声明周期内,它所管理的锁对象会一直保持上锁状态,而lock_guar=生命周期结束后,它所管理的锁对象会被解锁. 模板Mutex代表互斥量类型,例如std::mutex类型,它应该是一个基本的BasicLockable类型
* 在 lock_guard 对象构造时,传入的 Mutex 对象(即它所管理的 Mutex 对象)会被当前线程锁住。在lock_guard 对象被析构时,它所管理的 Mutex 对象会自动解锁,由于不需要程序员手动调用 lock 和 unlock 对 Mutex 进行上锁和解锁操作,因此这也是最简单安全的上锁和解锁方式,尤其是在程序抛出异常后先前已被上锁的 Mutex 对象可以正确进行解锁操作,极大地简化了程序员编写与 Mutex 相关的异常处理代码。
lock_guard 构造函数
locking(1) explicit lock_guard(mutex_type& m);
adopting(2) lock_guard(mutex_type& m,adopt_lock_t tag);
copy deleted lock_guard(const lock_guard&)=delete;
1.locking初始化:
lock_guard 对象管理Mutex对象m,并在构造时对m进行上锁(调用m.lock()).
2.adopting初始化
lock_guard对象管理Mutex对象m,与locking初始化(1)不同的是,Mutex对象m已被当前线程锁住.
3.拷贝构造
lock_guard对象的拷贝构造和移动构造都被禁用,因此lock_guard对象不可被拷贝构造或移动构造.
std::unique_lock介绍
- unique_lock 对象以独占所有权的方式管理 mutex 对象的上锁和解锁操作就是没有其他的 unique_lock 对象同时拥有某个 mutex 对象的所有权。
- 在构造(或移动(move)赋值)时,unique_lock 对象需要传递一个 Mutex 对象作为它的参数,新创建的 unique_lock 对象负责传入的 Mutex 对象的上锁和解锁操作.
unique_lock 不同于lock_guard的用法.
unique_lock的构造函数
- default(1) unique_lock noexcept;
- locking(2) explicit unique_lock(mutex_type & m);
- try-locking(3) unique_lock(mute