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 <iostream>
#include <chrono>
#include <thread>
#include <mutex>
#include <stdio.h>
#include <Windows.h>

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::recursive_mutex> 

std::lock_guard在构造函数中加锁,在析构函数中解锁,利用这个类可以减少我们对加锁可解锁操作的管理工作,专注于逻辑实现。

lock_guard类结构如下

template<typename _Mutex>
    class 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;
    };

可以很清楚的看到加锁和解锁过程
 

  • 1
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值