Loading... `std::lock` 是一个 C++ 用于避免死锁的工具,用于一次性锁住多个互斥锁(std::mutex),它通过确保锁定顺序一致,避免了死锁的发生。死锁是指程序中有多个共享资源,通常情况下,多个共享资源需要多个互斥锁来保护,以确保线程在访问这些资源时不会发生冲突。如果两个或更多线程在相互等待对方释放锁,就会导致它们无法继续执行,最终造成程序停滞或卡死。 # 一、死锁代码 ```cpp #include <iostream> #include <thread> #include <mutex> #include <chrono> std::mutex mutex1; std::mutex mutex2; void thread1_func() { std::lock_guard<std::mutex> lock1(mutex1); std::this_thread::sleep_for(std::chrono::milliseconds(100)); std::lock_guard<std::mutex> lock2(mutex2); std::cout << "Thread 1 acquired both mutexes\\n"; } void thread2_func() { std::lock_guard<std::mutex> lock2(mutex2); std::this_thread::sleep_for(std::chrono::milliseconds(100)); std::lock_guard<std::mutex> lock1(mutex1); std::cout << "Thread 2 acquired both mutexes\\n"; } int main() { std::thread t1(thread1_func); std::thread t2(thread2_func); t1.join(); t2.join(); return 0; } ``` 产生了死锁 # 二、**std::lock 解决死锁** ```cpp #include <iostream> #include <thread> #include <mutex> #include <chrono> std::mutex mutex1; std::mutex mutex2; void thread1_func() { std::lock(mutex1, mutex2); std::lock_guard<std::mutex> lock1(mutex1, std::adopt_lock); std::lock_guard<std::mutex> lock2(mutex2, std::adopt_lock); std::cout << "Thread 1 acquired both mutexes\\n"; } void thread2_func() { std::lock(mutex1, mutex2); std::lock_guard<std::mutex> lock1(mutex1, std::adopt_lock); std::lock_guard<std::mutex> lock2(mutex2, std::adopt_lock); std::cout << "Thread 2 acquired both mutexes\\n"; } int main() { std::thread t1(thread1_func); std::thread t2(thread2_func); t1.join(); t2.join(); return 0; } ``` `std::lock(mutex1, mutex2);` 的作用是同时锁定多个互斥锁,避免死锁的发生。它会阻塞直到所有指定的锁都被成功获取。 但是,`std::lock` 本身并不管理锁的释放,需要程序员手动释放锁。为了确保锁在作用域结束时自动释放,必须使用 `std::lock_guard` 或其他锁管理类。 这里使用 `std::lock_guard<std::mutex> lock1(mutex1, std::adopt_lock);` 和 `std::lock_guard<std::mutex> lock2(mutex2, std::adopt_lock);` 是告诉 `lock_guard` 这两个锁已经被锁定(由 `std::lock` 锁定),`lock_guard` 只负责在析构时释放它们。 总结:`std::lock` 负责安全地同时锁定多个互斥锁,`std::lock_guard` 负责自动释放锁,二者结合使用可以避免死锁并保证锁的正确释放。 # 三、源码实现 ```cpp template <class _Lock0, class _Lock1> bool _Lock_attempt_small(_Lock0& _Lk0, _Lock1& _Lk1) { _Lk0.lock(); { _Unlock_one_guard<_Lock0> _Guard{_Lk0}; if (_Lk1.try_lock()) { _Guard._Lk_ptr = nullptr; return false; } } _STD this_thread::yield(); return true; } template <class _Lock0, class _Lock1> void _Lock_nonmember1(_Lock0& _Lk0, _Lock1& _Lk1) { while (_Lock_attempt_small(_Lk0, _Lk1) && _Lock_attempt_small(_Lk1, _Lk0)) {} } _EXPORT_STD template <class _Lock0, class _Lock1, class... _LockN> void lock(_Lock0& _Lk0, _Lock1& _Lk1, _LockN&... _LkN) { _Lock_nonmember1(_Lk0, _Lk1, _LkN...); } ``` * \_Lock\_nonmember1 调用 \_Lock\_attempt\_small 函数尝试同时对多个锁进行加锁 * \_Lock\_attempt\_small 函数中: * 首先,对其中的任意一个锁进行加锁 * 然后,尝试对另外一个锁进行加锁,如果成功,则返回 false。\_Lock\_nonmember1 函数中的 while 循环退出。继续执行当前线程后续代码 * 如果加锁失败,则对第一个锁进行释放锁的操作。并且主动放弃剩余的时间片,等待操作系统再次调度执行当前线程,相当于等待一段时间,再重新尝试对两个锁进行加锁操作。 最后修改:2025 年 07 月 13 日 © 允许规范转载 打赏 赞赏作者 支付宝微信 赞 如果觉得我的文章对你有用,请随意赞赏