如何修复C++线程死锁示例
How to fix a C++ thread deadlock example
我设计了一个C++11线程死锁。这是通过使用具有多个线程池的两个独立函数来实现的。如何修复此示例以避免死锁?我认为解决方案与锁定程序的一致顺序有关。
#include <thread>
#include <mutex>
#include <iostream>
std::mutex kettle;
std::mutex tap;
#define THREAD_POOL 8
void kettle_tap(){
std::cout << "Locking kettle in " << std::this_thread::get_id() << std::endl;
// Lock the mutex kettle by creating and using lock_guard kettle_lock.
std::lock_guard<std::mutex> kettle_lock(kettle);
std::cout << "Locked kettle in " << std::this_thread::get_id() << std::endl;
std::cout << "Locking tap in " << std::this_thread::get_id() << std::endl;
// Lock the mutex tap by creating and using lock_guard tap_lock.
std::lock_guard<std::mutex> tap_lock(tap);
std::cout << "Locked tap in " << std::this_thread::get_id() << std::endl;
std::cout << "Filling kettle in " << std::this_thread::get_id() << std::endl;
}
void tap_kettle(){
std::cout << "Locking tap in " << std::this_thread::get_id() << std::endl;
// Lock the mutex tap by creating and using lock_guard tap_lock.
std::lock_guard<std::mutex> tap_lock(tap);
std::cout << "Locked tap in " << std::this_thread::get_id() << std::endl;
std::cout << "Locking kettle in " << std::this_thread::get_id() << std::endl;
// Lock the mutex kettle by creating and using lock_guard kettle_lock.
std::lock_guard<std::mutex> kettle_lock(kettle);
std::cout << "Locked kettle in " << std::this_thread::get_id() << std::endl;
std::cout << "Filling kettle in " << std::this_thread::get_id() << std::endl;
}
int main(){
std::thread pool[THREAD_POOL];
for (int t = 0; t < THREAD_POOL; t += 2){
pool[t] = std::thread(kettle_tap);
pool[t+1] = std::thread(tap_kettle);
}
for (int t = 0; t < THREAD_POOL; ++t){
pool[t].join();
}
std::cout << "Threads are all joined" << std::endl;
return 0;
}
std::lock(Mutexes...)
在您的情况下,kettle_tap()
和tap_kettle()
都应该以开头
std::lock(tap, kettle);
但是互斥参数的顺序并不重要,因此在两个函数之间可能会有不同。
锁定多个互斥对象
锁定作为参数传递的所有对象,必要时阻塞调用线程。
该函数使用对对象成员lock、try_lock和unlock的未指定调用序列来锁定对象,以确保所有参数在返回时都被锁定(不会产生任何死锁)。
如果函数无法锁定所有对象(例如,因为它的一个内部调用引发了异常),则函数会在失败之前首先解锁它成功锁定的所有对象(如果有的话)。
稍后,如果您想将锁的所有权转移到std::lock_guard
:
std::lock(tap, kettle);
std::lock_guard<std::mutex> kettle_lock(kettle, std::adopt_lock);
std::lock_guard<std::mutex> tap_lock(tap, std::adopt_lock);
你说得对。死锁可以通过避免循环等待来防止。在您的示例中,为了避免死锁,请在tap_kettle
方法中将kettle_lock
移动到tap_lock
之上。这样可以得到部分排序。
相关文章:
- 用C++中的std::condition_variable将线程置于死锁中会有风险吗
- localtime() 函数正在调用 ___lll_lock_wait_private(),这会使线程陷入死锁
- Qt:向死/停止线程发送信号
- 多线程Windows GUI应用程序中的死锁
- 死锁使用 std::mutex 来保护多个线程中的 cout
- 一个线程提升的死锁
- 是否访问指针元组和互斥锁线程安全
- C++互斥锁线程优先级
- 解决死锁问题,在主线程中等待多个工作线程完成 (C++11)
- 为什么我的程序在拥有线程的情况下生成LdrpLoaderLock死锁
- 避免单个线程中的死锁
- 这个简单的(原子)锁线程安全吗
- 线程tcp服务器死锁
- 线程安全std::cout的死锁
- 提升线程死锁,任何人都可以检查原因
- 如何在 QT 中使用互斥锁线程开始轮询
- 无锁线程池
- FFMPEG:多线程解码死锁
- 如何在C++Qt程序中调试多线程死锁
- 这种类型的编码是线程安全的还是死锁安全的