导读:本期聚焦于小伙伴创作的《C++中的std::recursive_mutex有什么用?允许同一线程多次加锁吗》,敬请观看详情,探索知识的价值。以下视频、文章将为您系统阐述其核心内容与价值。如果您觉得《C++中的std::recursive_mutex有什么用?允许同一线程多次加锁吗》有用,将其分享出去将是对创作者最好的鼓励。

std::recursive_mutex是C++标准库提供的递归互斥锁,属于<mutex>头文件中的组件,它的核心特性是允许同一个线程对同一个互斥锁对象进行多次加锁操作,而不会因为重复获取锁导致死锁。

C++中的std::recursive_mutex有什么用?允许同一线程多次加锁吗

std::recursive_mutex的核心作用

普通互斥锁std::mutex不允许同一个线程重复加锁,如果同一个线程已经持有锁,再次尝试加锁会直接阻塞或者返回错误,这会导致递归函数调用或者嵌套加锁的场景出现死锁。而std::recursive_mutex就是为了解决这类问题设计的,它的主要作用包括:

  • 支持递归函数的线程安全实现,递归函数在执行过程中会多次进入函数体,每次进入都需要获取锁保护共享资源,普通互斥锁无法满足这个需求。
  • 支持嵌套加锁场景,比如一个函数获取锁之后调用另一个也需要获取同一个锁的函数,普通互斥锁会导致死锁,递归互斥锁可以正常处理这种情况。
  • 在保证线程安全的前提下,简化复杂调用逻辑下的锁管理,避免开发者手动处理复杂的锁状态判断。

使用规则与注意事项

使用std::recursive_mutex需要遵循几个重要规则,否则还是会出现问题:

  • 同一个线程加锁多少次,就必须解锁多少次,否则其他线程永远无法获取这个锁。比如线程A加了3次锁,那么必须调用3次unlock,锁才会真正释放。
  • 不同线程之间的加锁操作仍然是互斥的,只有同一个线程的重复加锁才会被允许,其他线程尝试加锁时如果锁已经被持有,还是会进入阻塞状态。
  • 不要滥用递归互斥锁,因为维护递归计数会带来一定的性能开销,如果不需要重复加锁的场景,优先使用普通std::mutex。

代码示例

下面通过一个递归函数的例子展示std::recursive_mutex的用法,这个例子中递归函数会多次进入,每次都需要获取锁来保护共享计数器:

#include <iostream>
#include <mutex>
#include <thread>

// 定义递归互斥锁
std::recursive_mutex rec_mtx;
// 共享计数器
int shared_counter = 0;

// 递归函数,会重复获取同一个锁
void recursive_func(int depth) {
    // 第一次加锁
    rec_mtx.lock();
    std::cout << "线程 " << std::this_thread::get_id() << " 进入递归,深度: " << depth << std::endl;
    shared_counter++;
    
    if (depth > 0) {
        // 递归调用,再次尝试加锁同一个递归互斥锁,不会死锁
        recursive_func(depth - 1);
    }
    
    std::cout << "线程 " << std::this_thread::get_id() << " 离开递归,深度: " << depth << std::endl;
    // 对应一次加锁的解锁操作
    rec_mtx.unlock();
}

int main() {
    // 创建两个线程执行递归函数
    std::thread t1(recursive_func, 2);
    std::thread t2(recursive_func, 2);
    
    t1.join();
    t2.join();
    
    std::cout << "最终共享计数器的值: " << shared_counter << std::endl;
    return 0;
}

上面的代码中,recursive_func是递归函数,每次进入都会调用lock获取rec_mtx锁,递归调用时再次获取同一个锁不会死锁,因为rec_mtx是std::recursive_mutex类型。每次lock都对应一次unlock,最终两个线程执行完成后,shared_counter的值会是4,符合预期。

与普通std::mutex的对比

两者的核心区别可以通过以下表格清晰展示:

特性std::mutexstd::recursive_mutex
同一线程重复加锁不允许,会导致死锁或错误允许,需要记录加锁次数
加锁解锁次数要求加锁和解锁次数必须相等,且同一线程只能解锁自己加的锁同一线程加锁次数和解锁次数必须完全相等,否则锁无法释放
性能开销较小,无额外计数逻辑稍大,需要维护线程ID和加锁计数
适用场景无嵌套、无递归的普通加锁场景递归调用、嵌套加锁的场景

适用场景总结

std::recursive_mutex适合以下场景使用:

  • 函数存在递归调用,且递归过程中需要反复获取同一个锁保护共享资源。
  • 多个函数之间存在嵌套调用关系,且这些函数都需要获取同一个锁。
  • 无法确定调用链是否会重复获取同一个锁的复杂业务逻辑,且可以接受一定的性能开销。

如果可以提前梳理清楚调用逻辑,避免重复加锁,还是优先选择普通std::mutex,这样能获得更好的性能。另外也可以使用std::unique_lock配合std::recursive_mutex,利用RAII机制自动管理加锁解锁,避免忘记解锁的问题,比如下面的写法:

#include <mutex>
#include <unique_lock>

std::recursive_mutex rec_mtx;

void safe_func() {
    // 使用unique_lock自动管理锁,离开作用域自动解锁
    std::unique_lock<std::recursive_mutex> lock(rec_mtx);
    // 业务逻辑
    // 即使这里再次调用需要加锁的函数,也不会死锁
    // 离开作用域时,unique_lock会自动调用unlock,次数和加锁次数匹配
}

std::recursive_mutexC++多线程互斥锁修改时间:2026-07-23 19:09:28

免责声明:​ 已尽一切努力确保本网站所含信息的准确性。网站内容多为原创整理与精心编撰,观点力求客观中立。本站旨在免费分享,内容仅供个人学习、研究或参考使用。若引用了第三方作品,版权归原作者所有。如内容涉及您的权益,请联系我们处理。
内容垂直聚焦
专注技术核心技术栏目,确保每篇文章深度聚焦于实用技能。从代码技巧到架构设计,为用户提供无干扰的纯技术知识沉淀,精准满足专业提升需求。
知识结构清晰
覆盖从开发到部署的全链路。AI、前端、编程、数据库、服务器、建站、系统层层递进,构建清晰学习路径,帮助用户系统化掌握开发与运维所需的核心技术。
深度技术解析
拒绝泛泛而谈,深入技术细节与实践难点。无论是数据库优化还是服务器配置,均结合真实场景与代码示例进行剖析,致力于提供可直接应用于工作的解决方案。
专业领域覆盖
精准对应开发生命周期。从前端界面到后端编程,从数据库操作到服务器运维,形成完整闭环,一站式满足全栈工程师和运维人员的技术需求。
即学即用高效
内容强调实操性,步骤清晰、代码完整。用户可根据教程直接复现和应用于自身项目,显著缩短从学习到实践的距离,快速解决开发中的具体问题。
持续更新保障
专注既定技术方向进行长期、稳定的内容输出。确保各栏目技术文章持续更新迭代,紧跟主流技术发展趋势,为用户提供经久不衰的学习价值。