You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在C++中实现简单死锁?附相关代码片段

这段C++代码能触发死锁吗?

答案是肯定的,这段代码完全踩中了死锁的所有必要条件,几乎每次运行都会直接卡死。

先把你没写完的代码补全为可运行的完整版本:

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

std::mutex m1;
std::mutex m2;

auto f1 = [&m1, &m2]() {
    std::lock_guard<std::mutex> lg1(m1);
    std::this_thread::sleep_for(std::chrono::milliseconds(10));
    std::lock_guard<std::mutex> lg2(m2);
    std::cout << "A";
};

auto f2 = [&m1, &m2]() {
    std::lock_guard<std::mutex> lg1(m2);
    std::this_thread::sleep_for(std::chrono::milliseconds(10));
    std::lock_guard<std::mutex> lg2(m1);
    std::cout << "B";
};

int main() {
    std::thread t1(f1);
    std::thread t2(f2);
    t1.join();
    t2.join();
    return 0;
}

为什么会触发死锁?

死锁的四个必要条件这段代码全满足:

  • 互斥条件:std::mutex本身就是互斥资源,同一时间只能被一个线程持有;
  • 持有并等待:线程1拿到m1后,等着拿m2;线程2拿到m2后,等着拿m1;
  • 不可剥夺:std::lock_guard持有的锁不能被其他线程强行夺走,只能由持有线程主动释放;
  • 循环等待:线程1依赖线程2持有的m2,线程2依赖线程1持有的m1,形成了循环依赖链。

中间的sleep_for更是给死锁上了“保险”——它确保两个线程有足够的时间分别拿到第一个锁,然后同时卡在第二个锁的获取步骤上,几乎不会出现侥幸绕过的情况。

怎么避免这个死锁?

最常用的两种解决方案:

  • 固定锁的获取顺序:让两个线程都严格按照先m1后m2的顺序获取锁,直接打破循环等待的条件;
  • 用std::lock批量获取锁:这个函数内部会用避免死锁的算法来获取多个锁,示例代码如下:
    auto f1 = [&m1, &m2]() {
        std::lock(m1, m2);
        std::lock_guard<std::mutex> lg1(m1, std::adopt_lock);
        std::lock_guard<std::mutex> lg2(m2, std::adopt_lock);
        std::cout << "A";
    };
    auto f2 = [&m1, &m2]() {
        std::lock(m1, m2);
        std::lock_guard<std::mutex> lg1(m1, std::adopt_lock);
        std::lock_guard<std::mutex> lg2(m2, std::adopt_lock);
        std::cout << "B";
    };
    

内容的提问来源于stack exchange,提问作者Witnes

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.20 10:38:44