【编程】-常见的死锁在ubuntu下的验证代码

以下是几种常见死锁场景的C++示例代码,包含编译运行说明和死锁原理分析,适合在Ubuntu系统下验证:

  1. 互斥锁顺序死锁(最常见)
    代码示例
cpp
#include <iostream>
#include <thread>
#include <mutex>

std::mutex mutex1, mutex2;

void thread1() {
    mutex1.lock();
    std::cout << "Thread1 locked mutex1" << std::endl;
    std::this_thread::sleep_for(std::chrono::seconds(1)); // 确保死锁发生
    mutex2.lock(); // 阻塞在此
    std::cout << "Thread1 locked mutex2" << std::endl;
    mutex2.unlock();
    mutex1.unlock();
}

void thread2() {
    mutex2.lock();
    std::cout << "Thread2 locked mutex2" << std::endl;
    std::this_thread::sleep_for(std::chrono::seconds(1));
    mutex1.lock(); // 阻塞在此
    std::cout << "Thread2 locked mutex1" << std::endl;
    mutex1.unlock();
    mutex2.unlock();
}

int main() {
    std::thread t1(thread1);
    std::thread t2(thread2);
    t1.join();
    t2.join();
    return 0;
}
验证方法
bash
# 编译运行
g++ -std=c++11 -pthread deadlock1.cpp -o deadlock1
./deadlock1

现象:程序卡住无输出,用top查看CPU占用率为0,gdb attach可看到两个线程都在lock()处阻塞。

  1. 条件变量死锁(生产者消费者问题错误实现)
    代码示例
cpp
#include <iostream>
#include <thread>
#include <mutex>
#include <condition_variable>

std::mutex mtx;
std::condition_variable cv;
bool ready = false;

void consumer() {
    std::unique_lock<std::mutex> lock(mtx);
    while(!ready) {
        cv.wait(lock); // 永久阻塞如果丢失通知
    }
    std::cout << "Consumed" << std::endl;
}

void producer() {
    std::this_thread::sleep_for(std::chrono::seconds(2)); // 模拟延迟
    {
        std::lock_guard<std::mutex> lock(mtx);
        ready = true;
    }
    // 忘记调用 cv.notify_one();
}

int main() {
    std::thread t1(consumer);
    std::thread t2(producer);
    t1.join();
    t2.join();
    return 0;
}
验证方法
bash
g++ -std=c++11 -pthread deadlock2.cpp -o deadlock2
./deadlock2

现象:程序卡住,消费者线程永远等待。用gdb查看会显示consumer线程停在wait()处。

  1. 递归锁滥用死锁
    代码示例
cpp
#include <iostream>
#include <mutex>

std::recursive_mutex rmtx;

void recursive(int n) {
    rmtx.lock();
    std::cout << "Locked, n=" << n << std::endl;
    if(n > 0) {
        recursive(n-1); // 递归调用
    }
    rmtx.unlock(); // 实际会少一次unlock
}

int main() {
    std::thread t(recursive, 3);
    t.join();
    
    // 其他线程尝试获取锁
    std::thread t2([]{
        rmtx.lock(); // 阻塞在此
        std::cout << "Never reached" << std::endl;
        rmtx.unlock();
    });
    t2.join();
    return 0;
}
验证方法
bash
g++ -std=c++11 -pthread deadlock3.cpp -o deadlock3
./deadlock3

现象:程序输出前3次锁记录后卡住,第二个线程无法获取锁。

  1. 哲学家就餐问题(经典死锁)
    代码示例
cpp
#include <iostream>
#include <thread>
#include <mutex>
#include <vector>

const int N = 5;
std::mutex forks[N];

void philosopher(int id) {
    int left = id;
    int right = (id + 1) % N;
    
    forks[left].lock();
    std::cout << "Philosopher " << id << " took left fork" << std::endl;
    std::this_thread::sleep_for(std::chrono::seconds(1));
    
    forks[right].lock(); // 阻塞在此
    std::cout << "Philosopher " << id << " took right fork" << std::endl;
    
    // 进餐代码...
    
    forks[right].unlock();
    forks[left].unlock();
}

int main() {
    std::vector<std::thread> philosophers;
    for(int i = 0; i < N; ++i) {
        philosophers.emplace_back(philosopher, i);
    }
    for(auto& t : philosophers) {
        t.join();
    }
    return 0;
}
验证方法
bash
g++ -std=c++11 -pthread deadlock4.cpp -o deadlock4
./deadlock4

现象:每个哲学家都持有一个叉子,程序完全卡住。

死锁检测工具

gdb调试:

bash
gdb -p <PID>
thread apply all bt # 查看所有线程堆栈
valgrind检测:

bash
valgrind --tool=drd ./deadlock1
Clang静态分析:

bash
clang++ --analyze -Xanalyzer -analyzer-output=text deadlock1.cpp
解决方案原则
锁顺序:全局规定锁的获取顺序(如按地址排序)

超时机制:使用try_lock_for替代lock

RAII:用std::lock_guard/std::unique_lock管理锁生命周期

避免嵌套锁:重构代码减少锁作用域

这些示例覆盖了大多数实际开发中的死锁场景,建议在Ubuntu 20.04+环境下测试,所有代码均需要-pthread编译选项。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值