使用scoped_lock避免死锁——C++17示例代码技术咨询
如何用std::scoped_lock规避C++中的锁顺序死锁?
嘿,这个问题我太熟了!你遇到的是典型的锁顺序死锁——当两个线程以相反的顺序获取互斥量时,就会卡住互相等待对方释放锁。好在C++17引入的std::scoped_lock就是专门解决这个问题的神器!
先拆解原代码的死锁根源
你给出的deadlock_func_1先锁定mut_a,睡眠100ms后再去锁mut_b;对应的另一个产生死锁的函数(比如deadlock_func_2)应该是先锁mut_b,再尝试锁mut_a。当这两个线程同时运行时:
- 线程1拿到
mut_a,等着拿mut_b - 线程2拿到
mut_b,等着拿mut_a
双方都不肯先释放手里的锁,直接陷入死锁。
用std::scoped_lock解决问题的核心逻辑
std::scoped_lock是C++17新增的锁管理器,它支持同时锁定多个互斥量,并且内部会采用避免死锁的算法(比如按互斥量的内存地址排序后再依次锁定)。不管你在不同线程里传入互斥量的顺序如何,它都会用一致的顺序去锁定,从根源上切断死锁的可能。
修改后的完整代码
#include <iostream> #include <mutex> #include <thread> using namespace std; using namespace chrono_literals; mutex mut_a; mutex mut_b; // 修复后的函数1:用scoped_lock同时锁定两个互斥量 static void safe_func_1() { cout << "safe f1 acquiring both mutexes..." << endl; scoped_lock lock{mut_a, mut_b}; // 一次性锁定,顺序不影响 this_thread::sleep_for(100ms); cout << "safe f1: got both mutexes, doing work..." << endl; } // 修复后的函数2:即使传入顺序相反,也不会死锁 static void safe_func_2() { cout << "safe f2 acquiring both mutexes..." << endl; scoped_lock lock{mut_b, mut_a}; // 顺序和func1相反,但scoped_lock会自动处理 this_thread::sleep_for(100ms); cout << "safe f2: got both mutexes, doing work..." << endl; } int main() { thread t1(safe_func_1); thread t2(safe_func_2); t1.join(); t2.join(); return 0; }
额外说明
scoped_lock和lock_guard一样,都是RAII风格的锁管理器,会在作用域结束时自动释放所有锁定的互斥量,不用手动解锁。- 如果你的编译器还不完全支持C++17,也可以用
std::lock函数配合lock_guard(需要用std::adopt_lock标记),但scoped_lock的写法更简洁安全。
内容的提问来源于stack exchange,提问作者jlakes85
相关产品推荐
相关产品推荐

