C++11提供如下4中语义的互斥量:
std::mutex:独占互斥量,不能递归使用。
std::timed_mutex:带超时的独占互斥量,不能递归使用。
std::recursive_mutex:递归互斥量。
std::recursive_timed_mutex:带超时的递归互斥量。
5.2.1 独占互斥量std::mutex
lock阻塞的;try_lock非阻塞的,尝试锁定互斥量,成功返回true,失败返回false。
std::mutex的基本用法:
#include <iostream>
#include <thread>
#include <mutex>
#include <chrono>
std::mutex g_lock;
void func()
{
g_lock.lock();
std::cout << "entered thread " << std::this_thread::get_id() << std::endl;
std::this_thread::sleep_for(std::chrono::seconds(1));
std::cout << "leaving thread " << std::this_thread::get_id() << std::endl;
g_lock.unlock();
}
int main()
{
std::thread t1(func);
std::thread t2(func);
std::thread t3(func);
t1.join();
t2.join();
t3.join();
return 0;
}
输出:
entered thread 10144
leaving thread 10144
entered thread 4188
leaving thread 4188
entered thread 3424
leaving thread 3424
使用lock_guard可以简化lock/unlock写法,且更安全。构造时加锁,析构时解锁。修改后如下:
void func()
{
std::lock_guard<std::mutex> locker(g_lock);
std::cout << "entered thread " << std::this_thread::get_id() << std::endl;
std::this_thread::sleep_for(std::chrono::seconds(1));
std::cout << "leaving thread " << std::this_thread::get_id() << std::endl;
}
5.2.2 递归互斥量std::recursive_mutex
递归锁允许同一个线程多次获得互斥锁,可以用来解决同一个线程多次获取互斥锁时死锁的问题。
使用std::mutex发生死锁的示例:
struct Complex {
std::mutex mutex;
int i;
Complex(): i(0) {}
void mul(int x) {
std::lock_guard<std::mutex> lock(mutex);
i *= x;
}
void div(int x) {
std::lock_guard<std::mutex> lock(mutex);
i /= x;
}
void both(int x, int y) {
std::lock_guard<std::mutex> lock(mutex);
mul(x);
div(y);
}
};
int main()
{
Complex complex;
complex.both(2 , 3);
return 0;
}
both先获取锁,没有释放,mul又获取锁时死锁。解决,一个办法是是使用递归锁。
struct Complex {
std::recursive_mutex mutex;
int i;
Complex(): i(0) {}
void mul(int x) {
std::lock_guard<std::recursive_mutex> lock(mutex);
i *= x;
}
void div(int x) {
std::lock_guard<std::recursive_mutex> lock(mutex);
i /= x;
}
void both(int x, int y) {
std::lock_guard<std::recursive_mutex> lock(mutex);
mul(x);
div(y);
}
};
int main()
{
Complex complex;
complex.both(2 , 3);
return 0;
}
注意,尽量不要使用递归锁,主要如下原因:
(1)需要递归锁的往往本身可以简化
(2)递归锁比独占锁效率低
(3)递归锁重复获得锁的次数未具体说明,一旦超过一定次数,再lock会抛出std::system错误
5.2.3 带超时的互斥量std::timed_mutex和std::recursive_timed_mutex
std::timed_mutex比std::mutex多了两个超时获取锁的接口:try_lock_for和try_lock_until,这两个接口用来设置获取互斥量的超时时间。
std::timed_mutex的基本用法:
std::timed_mutex mutex;
void work() {
std::chrono::milliseconds timeout(100);
while(ture) {
if (mutex.try_lock_or(timeout)) {
std::cout << std::this_thread::get_id() << ": do work with the mutex" << std::endl;
std::this_thread::sleep_for(std::chrono::milliseconds(250));
mutex.unlock();
} else {
std::cout << std::this_thread::get_id() << ": do work without the mutex" << std::endl;
std::this_thread::sleep_for(std::chrono::milliseconds(100));
}
}
}
int main() {
std::thread t1(work);
std::thread t2(work);
t1.join();
t2.join();
return 0;
}