文章目录一、死锁介绍产生死锁的四个条件二、死锁防治方法方法1统一加锁顺序2.超时机制3.按层级加锁4.无锁编程一、死锁介绍死锁是指两个或多个进程或线程在执行过程中因争夺资源而造成的一种互相等待的现象导致所有涉及的进程都无法继续执行下去。比如有两个线程都需要同时锁住两个互斥才可以进行某项操作但它们分别都只锁住了一个互斥都等着再给另一个互斥加锁。于是双方毫无进展因为它们同在苦苦等待对方解锁互斥。一个经典的比喻哲学家就餐问题5 位哲学家围坐圆桌每人左右各有一根筷子吃饭需要同时拿起左右两根筷子如果每个人都先拿左边的筷子再等右边的就会全部卡住无人能吃饭引发死锁。产生死锁的四个条件必须同时满足以下四点才会发生死锁条件说明是否可破坏1. 互斥条件Mutual Exclusion资源一次只能被一个进程使用如打印机、mutex❌ 通常不可破坏资源本质决定2. 占有并等待Hold and Wait进程已持有至少一个资源同时等待其他被占用的资源✅ 可破坏3. 非抢占条件No Preemption已分配的资源不能被强制收回只能由持有者主动释放✅ 可破坏4. 循环等待Circular Wait存在一个进程等待环P₁→P₂→…→Pₙ→P₁✅ 可破坏c代码示例#includethread#includemutexstd::mutex mtx1,mtx2;voidthread1(){std::lock_guardstd::mutexlock1(mtx1);// 先锁 mtx1std::this_thread::sleep_for(std::chrono::milliseconds(10));std::lock_guardstd::mutexlock2(mtx2);// 再锁 mtx2}voidthread2(){std::lock_guardstd::mutexlock2(mtx2);// 先锁 mtx2std::this_thread::sleep_for(std::chrono::milliseconds(10));std::lock_guardstd::mutexlock1(mtx1);// 再锁 mtx1}intmain(){std::threadt1(thread1);std::threadt2(thread2);t1.join();t2.join();// 程序可能永远卡住}再比如假设有两个账户 A 和 B两个线程同时进行转账线程1从 A 转账到 B线程2从 B 转账到 A每个账户有一个自己的 mutex 保护余额。如果各自先锁“源账户”再锁“目标账户”就可能死锁// 危险代码可能导致死锁classAccount{public:intbalance;mutablestd::mutex m;Account(intb):balance(b){}};voidtransfer(Accountfrom,Accountto,intamount){std::lock_guardstd::mutexlock1(from.m);// 先锁 fromstd::this_thread::sleep_for(std::chrono::milliseconds(10));// 模拟延迟std::lock_guardstd::mutexlock2(to.m);// 再锁 tofrom.balance-amount;to.balanceamount;}二、死锁防治方法方法1统一加锁顺序上述转账例子使用std::lock()std::adopt_lock来原子地锁定多个互斥量从而彻底避免死锁#includeiostream#includethread#includevector#includemutexclassAccount{public:mutablestd::mutex m;// 每个账户一个 mutexintbalance;Account(intinitial_balance):balance(initial_balance){}};voidtransfer(Accountfrom,Accountto,intamount){// 关键使用 std::lock 原子地锁定多个 mutexstd::lock(from.m,to.m);// 无死锁风险// 使用 adopt_lock 告诉 lock_guard锁已经 acquiredstd::lock_guardstd::mutexlock_from(from.m,std::adopt_lock);std::lock_guardstd::mutexlock_to(to.m,std::adopt_lock);// 执行转账临界区from.balance-amount;to.balanceamount;// lock_guard 析构时自动 unlock顺序无关}intmain(){AccountA(1000),B(1000),C(1000);// 启动多个并发转账线程std::vectorstd::threadthreads;// A ↔ B 转账threads.emplace_back([](){for(inti0;i500;i){transfer(A,B,1);transfer(B,A,1);}});// B ↔ C 转账threads.emplace_back([](){for(inti0;i500;i){transfer(B,C,1);transfer(C,B,1);}});// A ↔ C 转账threads.emplace_back([](){for(inti0;i500;i){transfer(A,C,1);transfer(C,A,1);}});// 等待所有线程完成for(autot:threads){t.join();}// 验证总金额守恒应为 3000inttotalA.balanceB.balanceC.balance;std::coutA: A.balance\n;std::coutB: B.balance\n;std::coutC: C.balance\n;std::coutTotal: total (should be 3000)\n;return0;}2.超时机制std::timed_mutex mtx;if(mtx.try_lock_for(std::chrono::seconds(1))){// 成功获取锁mtx.unlock();}else{// 超时放弃或重试}3.按层级加锁把应用程序分层并且明确每个互斥位于哪个层级。若某线程已对低层级互斥加锁则不准它再对高层级互斥加锁。具体做法是将层级的编号赋予对应层级应用程序上的互斥并记录各线程分别锁定了哪些互斥:#includeiostream#includethread#includemutex//层级锁classhierarchical_mutex{public:explicithierarchical_mutex(unsignedlongvalue):_hierarchy_value(value),_previous_hierarchy_value(0){}hierarchical_mutex(consthierarchical_mutex)delete;hierarchical_mutexoperator(consthierarchical_mutex)delete;voidlock(){check_for_hierarchy_violation();_internal_mutex.lock();update_hierarchy_value();}voidunlock(){if(_this_thread_hierarchy_value!_hierarchy_value){throwstd::logic_error(mutex hierarchy violated);}_this_thread_hierarchy_value_previous_hierarchy_value;_internal_mutex.unlock();}booltry_lock(){check_for_hierarchy_violation();if(!_internal_mutex.try_lock()){returnfalse;}update_hierarchy_value();returntrue;}private:std::mutex _internal_mutex;//当前层级值unsignedlongconst_hierarchy_value;//上一次层级值unsignedlong_previous_hierarchy_value;//本线程记录的层级值staticthread_localunsignedlong_this_thread_hierarchy_value;voidcheck_for_hierarchy_violation(){if(_this_thread_hierarchy_value_hierarchy_value){throwstd::logic_error(mutex hierarchy violated);}}voidupdate_hierarchy_value(){_previous_hierarchy_value_this_thread_hierarchy_value;_this_thread_hierarchy_value_hierarchy_value;}};thread_localunsignedlonghierarchical_mutex::_this_thread_hierarchy_value(ULONG_MAX);voidtest_hierarchy_lock(){hierarchical_mutexhmtx1(1000);hierarchical_mutexhmtx2(500);std::threadt1([hmtx1,hmtx2](){hmtx1.lock();hmtx2.lock();hmtx2.unlock();hmtx1.unlock();});std::threadt2([hmtx1,hmtx2](){hmtx2.lock();hmtx1.lock();hmtx1.unlock();hmtx2.unlock();});t1.join();t2.join();}层级锁能保证我们每个线程加锁时一定是先加权重高的锁。并且释放时也保证了顺序。主要原理就是将当前锁的权重保存在线程变量中这样该线程再次加锁时判断线程变量的权重和锁的权重是否大于如果满足条件则继续加锁4.无锁编程使用原子操作std::atomic、CAS 等高性能但复杂适用于特定场景