unique_lock在构造时的灵活性:
#include <iostream>
#include <Windows.h>
#include <mutex>
using namespace std;
void CriticalSection_2();
mutex m1;
void CriticalSection_1()
{
unique_lock<mutex> lockguard(m1);
CriticalSection_2();
}
void CriticalSection_2()
{
//场景一
//unique_lock<mutex> lockguard(m1); //崩溃,对已经加锁的 mutex 再加锁导致崩溃
//场景二
//unique_lock<mutex> lockguard(m1, try_to_lock_t()); //正常,对已经加锁的 mutex 尝试加锁不会导致崩溃
//场景三
//unique_lock<mutex> lockguard(m1, defer_lock_t()); //正常,对已经加锁的 mutex 不加锁不会崩溃
//m1.lock(); //奔溃,对已经加锁的 mutex 再加锁导致崩溃
//场景四
//unique_lock<mutex> lockguard(m1, adopt_lock_t()); //崩溃
}
int main()
{
CriticalSection_1();
std::cout << "Hello World!\n";
while (1) Sleep(1000);
}
unique_lock在使用中的灵活性:
- 可以随时解锁(lock_guard无法做到,虽然通过mutex.unlock()也可以完成,但是unique_lock提供了自释放功能)
#include <iostream>
#include <Windows.h>
#include <mutex>
using namespace std;
void CriticalSection_2();
mutex m1;
void CriticalSection_1()
{
unique_lock<mutex> lockguard(m1);
lockguard.unlock();
CriticalSection_2();
}
void CriticalSection_2()
{
unique_lock<mutex> lockguard(m1); //正常,前面已经通过lockguard.unlock();进行了解锁
}
int main()
{
CriticalSection_1();
std::cout << "Hello World!\n";
while (1) Sleep(1000);
}
- 析构时会自动判断当前是否持有锁(对已经释放的锁再释放会导致崩溃,unique_lock在析构函数中会判断当前锁是否已经被释放)
#include <iostream>
#include <Windows.h>
#include <mutex>
using namespace std;
mutex m1;
void CriticalSection_1()
{
unique_lock<mutex> lockguard(m1);
#if 1
lockguard.unlock(); //不会奔溃,虽然lockguard.unlock();被显式调用,但是lockguard析构不会导致崩溃
#else
m1.unlock(); //会崩溃,这里也要强调一点,如果打算使用unique_lock就不要在对原始的mutex进行任何操作
#endif
}
int main()
{
CriticalSection_1();
std::cout << "Hello World!\n";
while (1) Sleep(1000);
}
注意:
如果确定使用unique_lock了,就不要再使用 mutex 的 lock 和 unlock ,直接使用 unique_lock 的 lock 和 unlock,混合使用会导致程序异常,原因是unique_lock 内部会维护一个标识用来记录自己管理的 锁 当前处于何种状态,如果直接使用 mutex的成员函数,unique_lock无法更新自己的状态,从而导致 double lock 和 double unlock(因为unique_lock一定会在析构的时候unlock),这两种情况都会导致崩溃。
PS:
上面的崩溃不会发生在 递归锁上,所以上文中所有的锁 都是非递归锁,比如 mutex。
对比unique_lock 和 lock_guard:
- 二者都是自释放锁;
- lock_guard 在时间和空间上都比 unique_lock 要快;
- lock_guard 功能单一,只能用作自释放锁;
- unique_lock具备lock_guard的所有能力,同时提供更多的能力,比如锁的成员函数都会被封装后导出,同时不会引入 double lock 和 double unlock ;