
Mutex 又称互斥量,C++ 11中与 Mutex 相关的类(包括锁类型)和函数都声明在 <mutex> 头文件中,所以如果你需要使用 std::mutex,就必须包含 <mutex> 头文件。
C++11中新增了<mutex>,它是C++标准程序库中的一个头文件,定义了C++11标准中的一些互斥访问的类与方法等。
C++11标准库定义了4个互斥类:

std::mutex
std::mutex 是C++11 中最基本的互斥量,std::mutex 对象提供了独占所有权的特性——即不支持递归地对 std::mutex 对象上锁,而 std::recursive_lock 则可以递归地对互斥量对象上锁。
下面给出一个与 std::mutex 的小例子(http://www.cplusplus.com/reference/mutex/mutex/try_lock/):
// mutex::try_lock example#include <iostream> // std::cout#include <thread> // std::thread#include <mutex> // std::mutexvolatile int counter (0); // non-atomic counterstd::mutex mtx; // locks access to countervoid attempt_10k_increases () {for (int i=0; i<10000; ++i) {if (mtx.try_lock()) { // only increase if currently not locked:++counter;mtx.unlock();}}}int main (){std::thread threads[10];// spawn 10 threads:for (int i=0; i<10; ++i)threads[i] = std::thread(attempt_10k_increases);for (auto& th : threads) th.join();std::cout << counter << " successful increases of the counter.\n";return 0;}
std::recursive_mutex
官方文档是这么说的:
recursive_mutex 类是同步原语,能用于保护共享数据免受个多线程同时访问。
recursive_mutex 提供排他性递归所有权语义:
-
调用方线程在从它成功调用 lock 或 try_lock 开始的时期里占有 recursive_mutex 。此时期间,线程可以进行对 lock 或 try_lock 的附加调用。所有权的时期在线程调用 unlock 匹配次数时结束。
-
线程占有 recursive_mutex 时,若其他所有线程试图要求 recursive_mutex 的所有权,则它们将阻塞(对于调用 lock )或收到 false 返回值(对于调用 try_lock )。
-
可锁定 recursive_mutex 次数的最大值是未指定的,但抵达该数后,对 lock 的调用将抛出 std::system_error 而对 try_lock 的调用将返回 false 。
若 recursive_mutex 在仍为某线程占有时被销毁,则程序行为未定义。recursive_mutex 类满足互斥体 (Mutex) 和标准布局类型 (StandardLayoutType) 的所有要求。
用人话说就是:递归互斥锁可以被同一个线程多次加锁,以获得对互斥锁对象的多层所有权。例如,同一个线程多个函数访问临界区时都可以各自加锁,执行后各自解锁。std::recursive_mutex释放互斥量时需要调用与该锁层次深度相同次数的unlock(),即lock()次数和unlock()次数相同。可见,线程申请递归互斥锁时,如果该递归互斥锁已经被当前调用线程锁住,则不会产生死锁。
recursive_mutex 的使用场景之一是保护类中的共享状态,而类的成员函数可能相互调用。官方的小例子:
#include <iostream>#include <thread>#include <mutex>class X {std::recursive_mutex m;std::string shared;public:void fun1() {std::lock_guard<std::recursive_mutex> lk(m);shared = "fun1";std::cout << "in fun1, shared variable is now " << shared << '\n';}void fun2() {std::lock_guard<std::recursive_mutex> lk(m);shared = "fun2";std::cout << "in fun2, shared variable is now " << shared << '\n';fun1(); // 递归锁在此处变得有用std::cout << "back in fun2, shared variable is " << shared << '\n';};};int main(){X x;std::thread t1(&X::fun1, &x);std::thread t2(&X::fun2, &x);t1.join();t2.join();}
可以看出fun2调用的fun1,他们都对recursive_mutex m 加锁,如果不是recursive的,那么这里会产生死锁。假设fun2拿到了锁,然后调用fun1又要去拿锁,又不是recursive的,那么就会hang在fun1里边。
std::time_mutex
官方文档是这么说的:
recursive_timed_mutex 是同步原语,能用于保护共享数据免受从多个线程同时访问。
以类似 std::recursive_mutex 的方式, recursive_timed_mutex 提供排他性递归所有权语义。另外, recursive_timed_mutex 通过 try_lock_for 与 try_lock_until 方法,提供带时限地试图要求 recursive_timed_mutex 所有权的能力。
recursive_timed_mutex 类满足定时互斥体 (TimedMutex) 和标准布局类型 (StandardLayoutType) 的所有要求。
换成人话说:
std::time_mutex 比 std::mutex 多了两个成员函数,try_lock_for(),try_lock_until()。
try_lock_for 函数接受一个时间范围,表示在这一段时间范围之内线程如果没有获得锁则被阻塞住(与 std::mutex 的 try_lock() 不同,try_lock 如果被调用时没有获得锁则直接返回 false),如果在此期间其他线程释放了锁,则该线程可以获得对互斥量的锁,如果超时(即在指定时间内还是没有获得锁),则返回 false。
try_lock_until 函数则接受一个时间点作为参数,在指定时间点未到来之前线程如果没有获得锁则被阻塞住,如果在此期间其他线程释放了锁,则该线程可以获得对互斥量的锁,如果超时(即在指定时间内还是没有获得锁),则返回 false。
举个try_lock_for的小例子:
#include <iostream>#include <mutex>#include <thread>#include <vector>#include <sstream>std::mutex cout_mutex; // 控制到 std::cout 的访问std::timed_mutex mutex;void job(int id){using Ms = std::chrono::milliseconds;std::ostringstream stream;for (int i = 0; i < 3; ++i) {if (mutex.try_lock_for(Ms(100))) {stream << "success ";std::this_thread::sleep_for(Ms(100));mutex.unlock();} else {stream << "failed ";}std::this_thread::sleep_for(Ms(100));}std::lock_guard<std::mutex> lock(cout_mutex);std::cout << "[" << id << "] " << stream.str() << "\n";}int main(){std::vector<std::thread> threads;for (int i = 0; i < 4; ++i) {threads.emplace_back(job, i);}for (auto& i: threads) {i.join();}}
可能的输出:
[0] failed failed failed[3] failed failed success[2] failed success failed[1] success failed success
std::recursive_timed_mutex
这个就好说的,就是叠加recursive 和time两大神功的mutex。
986





