c++ 递归锁
递归锁RECURSIVE_MUTEX的原理以及使用
标签: Multi_Thread Recursive_Mutex
递归锁的作用
MutexLock mutex; void foo()
{ mutex.lock(); // do something mutex.unlock();
} void bar()
{ mutex.lock(); // do something foo(); mutex.unlock();
}
foo函数和bar函数都获取了同一个锁,而bar函数又会调用foo函数。如果MutexLock锁是个非递归锁,则这个程序会立即死锁。因此在为一段程序加锁时要格外小心,否则很容易因为这种调用关系而造成死锁。
不要存在侥幸心理,觉得这种情况是很少出现的。当代码复杂到一定程度,被多个人维护,调用关系错综复杂时,程序中很容易犯这样的错误。庆幸的是,这种原因造成的死锁很容易被排除。
但是这并不意味着应该用递归锁去代替非递归锁。递归锁用起来固然简单,但往往会隐藏某些代码问题。比如调用函数和被调用函数以为自己拿到了锁,都在修改同一个对象,这时就很容易出现问题。因此在能使用非递归锁的情况下,应该尽量使用非递归锁,因为死锁相对来说,更容易通过调试发现。程序设计如果有问题,应该暴露的越早越好。
本段参考链接
自制递归锁
#include"stdafx.h"
#include
#include
#include
#include
#include
#include using namespace std;int g_num = 0; // 为 g_num_mutex 所保护
recursive_mutex g_num_mutex;class RecursiveMutex {
public:RecursiveMutex() {num_of_locks = 0;}~RecursiveMutex() {}void lock() {if (num_of_locks == 0) {my_mutex.lock();owner_thread_id = GetCurrentThreadId();}else if (GetCurrentThreadId() == owner_thread_id)num_of_locks++;}void unlock() {if (num_of_locks > 0)num_of_locks--;if (num_of_locks == 0)my_mutex.unlock();}private:int num_of_locks;mutex my_mutex;int owner_thread_id;
};RecursiveMutex myRecursiveMutex;void slow_increment_stl(int id)
{for (int i = 0; i < 3; ++i) {g_num_mutex.lock();++g_num;std::cout << id << " => " << g_num << '\n';g_num_mutex.unlock();std::this_thread::sleep_for(std::chrono::seconds(2));}
}void slow_increment(int id)
{for (int i = 0; i < 3; ++i) {myRecursiveMutex.lock();++g_num;std::cout << id << " => " << g_num << '\n';myRecursiveMutex.unlock();std::this_thread::sleep_for(std::chrono::seconds(2));}
}int main()
{cout << "使用stl中的recursive_mutex" << endl;std::thread t1(slow_increment_stl, 0);std::thread t2(slow_increment_stl, 1);t1.join();t2.join();cout << "使用自写类RecursiveMutex" << endl;std::thread t3(slow_increment, 0);std::thread t4(slow_increment, 1);t3.join();t4.join();}

可见使用自制递归锁类与标准库中的递归锁类输出相同。
问题就是:加锁的操作需要相互嵌套,如果使用std::mutex 肯定会导致死锁,而重构代码,提取出共用部分的工作量又很大。
这个时候我发现了好东西 std::recursive_mutex 递归锁
递归锁可以允许一个线程对同一互斥量多次加锁,解锁时,需要调用与lock()相同次数的unlock()才能释放使用权
这边再介绍一个好东西:
std::lock_guard
std::lock_guard在构造函数中加锁,在析构函数中解锁,利用这个类可以减少我们对加锁可解锁操作的管理工作,专注于逻辑实现。
lock_guard类结构如下
templateclass lock_guard{public:typedef _Mutex mutex_type;explicit lock_guard(mutex_type& __m) : _M_device(__m){ _M_device.lock(); }lock_guard(mutex_type& __m, adopt_lock_t) : _M_device(__m){ } // calling thread owns mutex~lock_guard(){ _M_device.unlock(); }lock_guard(const lock_guard&) = delete;lock_guard& operator=(const lock_guard&) = delete;private:mutex_type& _M_device;};
可以很清楚的看到加锁和解锁过程
本文来自互联网用户投稿,文章观点仅代表作者本人,不代表本站立场,不承担相关法律责任。如若转载,请注明出处。 如若内容造成侵权/违法违规/事实不符,请点击【内容举报】进行投诉反馈!
