C++ 自己代码实现一个递归锁recursive_mutex

之前看过一篇博客讲递归锁的实现,博客链接https://blog.csdn.net/m18718300471/article/details/79927948

但是我测试发现博客中的递归锁实现有问题,因此自己写了一种实现,不一定是最好的,如果有人发现问题或者有更好的写法,欢迎指出来,大家一起讨论交流~

递归锁介绍

我们都知道,一般的互斥量对于同一个线程只能同时加锁一次(调用lock),如果连续调用两次以上便会出现死锁。你可能会问,为什么会连续调用两次呢,但设想这样一个场景,如果在一个函数内给互斥量上了锁还没有解开,然后又调用了另一个函数,这个被调用的函数也去给互斥量上锁,这种情境下就会出现死锁。看下面的例子:

MutexLock mutex;  

void foo()  
{  
    mutex.lock();  
    // do something  
    mutex.unlock();  
}  

void bar()  
{  
    mutex.lock();  
    // do something  
    foo();  
    mutex.unlock();   
}  

为了解决这个问题,引入了递归锁的概念。递归锁,顾名思义,如果因为多次函数调用而导致出现多次上锁的情况,只有第一次会去真正加锁,后面的加锁操作会被自动忽略。

递归锁实现

我自己实现了一个RecursiveMutex类,这个类里面三个私有成员:

1. mutex recursiveMutex:互斥量,使用此普通互斥量来实现一个递归锁

2. map lockNums:一个字典, key是线程id,value是该线程调用lock的次数,当第一次调用lock时真正调用recursiveMutex.lock(),否则就使该value值加一但是不去调用lock函数。

3. mutex mapMutex:一个互斥量,用来保护lockNums这个map,因为map也可能被多个线程访问,是共享资源,因此需要保护起来。

该类有两个公有函数,分别为lock以及unlock,可以被调用来加锁解锁。完整实现如下:

//
//  main.cpp
//  recersive_mutex
//  运行环境:mac os
//  有两部分,一部分是系统的recursive_mutex用法,另一部分是自己实现了一个recursive_mutex类
//  Created by Chaochun Ma on 6/23/20.
//  Copyright © 2020 Chaochun Ma. All rights reserved.
//
//总结:
//1. lock和unlock必须要成对使用,实测系统提供的recursive_mutex如果不成对使用也有可能死锁或者报异常
//2. 看过源码后lock_guard本质就是构造函数调用mutex.lock(),析构函数调用mutex.unlock(),所以当使用lock_guard创建对象后,同样再调用mutex.unlock()有可能会出错。


#include 
#include 
#include 
#include 
#include 
#include 
#include 

using namespace std;

int g_num;  // 为 g_num_mutex 所保护
recursive_mutex g_num_mutex;

class RecursiveMutex {
public:
    RecursiveMutex() {
        lockNums.clear();
    }

    ~RecursiveMutex() {

    }

    void lock() {
        mapMutex.lock();
        // 当前线程未获取过recursive_mutex
        if (lockNums.find(this_thread::get_id()) == lockNums.end() || lockNums[this_thread::get_id()] == 0)
        {
            lockNums[this_thread::get_id()] = 1;
            // 这里一定要先释放mapMutex锁,否则会出现死锁
            mapMutex.unlock();
            recursiveMutex.lock();
        }
        // 当前线程曾经获取过recursive_mutex
        else
        {
            lockNums[this_thread::get_id()] += 1;
            mapMutex.unlock();
        }
    }

    void unlock() {
        mapMutex.lock();
        if (lockNums.find(this_thread::get_id()) == lockNums.end() || lockNums[this_thread::get_id()] == 0)
        {
            mapMutex.unlock();
            cout << "recursive_mutex lock和unlock未成对使用!\n";
        }
        else
        {
            // 当前是最后一次调用,需要解锁
            if (lockNums[this_thread::get_id()] == 1)
            {
                lockNums.erase(this_thread::get_id());
                recursiveMutex.unlock();
            }
            else
            {
                lockNums[this_thread::get_id()] -= 1;
            }
            mapMutex.unlock();
        }
    }

private:
    mutex recursiveMutex;
    // 用来记录某一个线程使用recursiveMutex.lock()的次数
    map lockNums;
    mutex mapMutex;
};

RecursiveMutex myRecursiveMutex;

void slow_increment_stl(int id)
{
    for (int i = 0; i < 3; ++i) {
        g_num_mutex.lock();
        g_num_mutex.lock();
        ++g_num;
        std::cout << id << " => " << g_num << '\n';
        g_num_mutex.unlock();
        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();
        myRecursiveMutex.lock();
        ++g_num;
        std::cout << id << " => " << g_num << '\n';
        myRecursiveMutex.unlock();
        myRecursiveMutex.unlock();

        std::this_thread::sleep_for(std::chrono::seconds(2));
    }
}

int main()
{
//    使用系统自带的recursive_mutex
    g_num = 0;
    cout << "使用stl中的recursive_mutex" << endl;
    std::thread t1(slow_increment_stl, 0);
    std::thread t2(slow_increment_stl, 1);
    t1.join();
    t2.join();

//    使用自己实现的recursive_mutex
    g_num = 0;
    cout << "使用自写类RecursiveMutex" << endl;
    std::thread t3(slow_increment, 0);
    std::thread t4(slow_increment, 1);
    t3.join();
    t4.join();

}

实验结果

C++ 自己代码实现一个递归锁recursive_mutex_第1张图片

 

你可能感兴趣的:(C++,服务器)