C++多线程编程:其六、unique_lock的使用
一、异常导致没有解锁
mutex对象需要手动解锁。但是如果在解锁之前抛出来异常,就会导致解锁逻辑没有执行。当前线程就会一直占有互斥量,其它线程就一直无法得到互斥量,就无法执行,看代码:
#include <iostream>
#include <thread>
#include <mutex>
#include <stdexcept>
std::mutex mtx;
void print_event(int x)
{
if(x%2==0)
std::cout << x << " is even\n";
else
throw (std::logic_error("not even"));
}
void print_thread_id(int id)
{
try{
mtx.lock();
print_event(id);
mtx.unlock();
}
catch(std::logic_error&)
{
std::cout << "[exception caught]\n";
}
}
int main(int argc,char **argv)
{
std::thread threads[10];
for(int i=0;i<10;i++)
{
threads[i]=std::thread(print_thread_id,i+1);
}
for (auto& th : threads) th.join();
return 0;
}
执行后会发现程序被卡主,因为发生了死锁。
二、基于RAII思想的unique_lock
unique_lock在构造的时候传入mutex变量,对mutex变量加锁。在析构的时候对这个mutex变量解锁,从而实现了自动解锁。print_thread_id函数的代码可以替换为::
void print_thread_id(int id)
{
try{
std::unique_lock<std::mutex> ul(mtx);
print_event(id);
}
catch(std::logic_error&)
{
std::cout << "[exception caught]\n";
}
}
输出结果:
[exception caught]
[exception caught]
2 is even
4 is even
[exception caught]
6 is even
[exception caught]
8 is even
[exception caught]
10 is even
死锁解除。