Linux C++ 编程死锁详解

🎓作者简介:程序员项目管理领域优质创作者

💌个人邮箱:2707492172@qq.com

🌐PMP资料导航:PM菜鸟查阅PMP大纲考点

💡座右铭:上善若水,水善利万物而不争。

🌐绿泡泡:PM简读馆(包含更多PM常用免费资料)

目录

概要

一、死锁的四个必要条件

二、常见死锁场景

三、代码解释

1、资源申请顺序不一致

问题描述

解决方案

[2. 优先级倒置](#2. 优先级倒置)

问题描述

解决方案

[3. 线程间循环等待](#3. 线程间循环等待)

问题描述

解决方案

[4. 锁嵌套(Lock Nesting)](#4. 锁嵌套(Lock Nesting))

问题描述

解决方案


概要

在多线程编程的领域中,死锁是一个经典顽疾 。当多个线程因资源争夺陷入永久等待 ,所有线程都会集体 "冻住"。就像两人过桥面宽度 = 1 的独木桥:左行的 A 和右行的 B 在桥中相遇,谁都不退让,最终双双困在桥面 ------ 这正是循环等待条件的现实映射。

程序中的死锁常发生于交叉持锁场景:线程 A 已握互斥锁 1(pthread_mutex_lock (1)),试图获取锁 2;线程 B 正持有锁 2,同时等待锁 1。此时内核调度若恰好切换线程,双方将陷入 "你等我放锁,我等你松手" 的僵局,CPU 空转但任务停滞。

死锁的破坏力极具隐蔽性:服务器可能 100% CPU 空转却无业务响应,嵌入式系统突然 "死机" 却无报错日志。这类时序相关的逻辑错误,无法通过单步调试发现,必须依赖系统级排查工具。

一、死锁的四个必要条件

先认识一些死锁的发生需要满足哪几个条件:

  1. 互斥(Mutual Exclusion):资源一次只能被一个线程使用。
  2. 持有并等待(Hold and Wait):线程在持有资源的同时,请求其他资源。
  3. 不剥夺(No Preemption):资源不能被强制剥夺,只能由持有者主动释放。
  4. 循环等待(Circular Wait):线程之间形成一个环,每个线程都在等待下一个线程释放资源。

二、常见死锁场景

在Linux C++编程中,以下场景容易导致死锁:

  1. 资源申请顺序不一致:多个线程以不同的顺序申请相同的资源。
  2. 优先级倒置:高优先级线程被低优先级线程占用资源,导致阻塞。
  3. 线程间循环等待:线程A等待线程B释放资源,线程B又在等待线程A释放资源。
  4. 锁嵌套(Lock Nesting):在一个锁的保护范围内申请另一个锁,导致锁顺序不一致。

三、代码解释

1、资源申请顺序不一致

问题描述

多个线程以不同的顺序申请相同的资源,导致死锁。

cpp 复制代码
#include <mutex>
#include <thread>
#include <iostream>

std::mutex mutex1, mutex2;

void threadA() {
    std::lock_guard<std::mutex> lock1(mutex1);
    std::this_thread::sleep_for(std::chrono::milliseconds(100));
    std::lock_guard<std::mutex> lock2(mutex2);
    // 临界区代码
}

void threadB() {
    std::lock_guard<std::mutex> lock2(mutex2);
    std::this_thread::sleep_for(std::chrono::milliseconds(100));
    std::lock_guard<std::mutex> lock1(mutex1);
    // 临界区代码
}

int main() {
    std::thread t1(threadA);
    std::thread t2(threadB);
    t1.join();
    t2.join();
    return 0;
}
解决方案

确保所有线程以相同的顺序申请锁:

cpp 复制代码
#include <mutex>
#include <thread>
#include <iostream>

std::mutex mutex1, mutex2;

void acquire_locks(std::mutex& lock1, std::mutex& lock2) {
    if (&lock1 > &lock2) {
        std::lock_guard<std::mutex> lock(lock1);
        std::lock_guard<std::mutex> lock2(lock2);
    } else {
        std::lock_guard<std::mutex> lock(lock2);
        std::lock_guard<std::mutex> lock1(lock1);
    }
}

void thread_function() {
    acquire_locks(mutex1, mutex2);
    // 临界区代码
}

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

2. 优先级倒置

问题描述

高优先级线程被低优先级线程占用资源,导致阻塞。

cpp 复制代码
#include <pthread.h>
#include <iostream>
#include <unistd.h>

pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;

void* high_priority_thread(void* arg) {
    // 设置高优先级
    struct sched_param param;
    param.sched_priority = 50;
    pthread_setschedparam(pthread_self(), SCHED_FIFO, &param);

    // 尝试获取锁
    while (true) {
        pthread_mutex_lock(&mutex);
        std::cout << "High priority thread acquired lock." << std::endl;
        pthread_mutex_unlock(&mutex);
        sleep(1);
    }
}

void* low_priority_thread(void* arg) {
    // 设置低优先级
    struct sched_param param;
    param.sched_priority = 10;
    pthread_setschedparam(pthread_self(), SCHED_FIFO, &param);

    // 尝试获取锁
    while (true) {
        pthread_mutex_lock(&mutex);
        std::cout << "Low priority thread acquired lock." << std::endl;
        sleep(1);
        pthread_mutex_unlock(&mutex);
    }
}

int main() {
    pthread_t t1, t2;
    pthread_create(&t1, NULL, high_priority_thread, NULL);
    pthread_create(&t2, NULL, low_priority_thread, NULL);
    pthread_join(t1, NULL);
    pthread_join(t2, NULL);
    return 0;
}
解决方案

使用优先级继承协议:

cpp 复制代码
#include <pthread.h>
#include <iostream>
#include <unistd.h>

pthread_mutex_t mutex;
pthread_mutexattr_t attr;

void* high_priority_thread(void* arg) {
    // 设置高优先级
    struct sched_param param;
    param.sched_priority = 50;
    pthread_setschedparam(pthread_self(), SCHED_FIFO, &param);

    // 尝试获取锁
    while (true) {
        pthread_mutex_lock(&mutex);
        std::cout << "High priority thread acquired lock." << std::endl;
        pthread_mutex_unlock(&mutex);
        sleep(1);
    }
}

void* low_priority_thread(void* arg) {
    // 设置低优先级
    struct sched_param param;
    param.sched_priority = 10;
    pthread_setschedparam(pthread_self(), SCHED_FIFO, &param);

    // 尝试获取锁
    while (true) {
        pthread_mutex_lock(&mutex);
        std::cout << "Low priority thread acquired lock." << std::endl;
        sleep(1);
        pthread_mutex_unlock(&mutex);
    }
}

int main() {
    // 初始化mutex属性
    pthread_mutexattr_init(&attr);
    pthread_mutexattr_setprotocol(&attr, PTHREAD_PRIO_INHERIT);
    pthread_mutex_init(&mutex, &attr);

    pthread_t t1, t2;
    pthread_create(&t1, NULL, high_priority_thread, NULL);
    pthread_create(&t2, NULL, low_priority_thread, NULL);
    pthread_join(t1, NULL);
    pthread_join(t2, NULL);

    pthread_mutexattr_destroy(&attr);
    pthread_mutex_destroy(&mutex);
    return 0;
}

3. 线程间循环等待

问题描述

线程A等待线程B释放资源,线程B又在等待线程A释放资源。

cpp 复制代码
#include <mutex>
#include <thread>
#include <iostream>

std::mutex mutex1, mutex2;

void threadA() {
    std::lock_guard<std::mutex> lock1(mutex1);
    std::this_thread::sleep_for(std::chrono::milliseconds(100));
    std::lock_guard<std::mutex> lock2(mutex2);
    // 临界区代码
}

void threadB() {
    std::lock_guard<std::mutex> lock2(mutex2);
    std::this_thread::sleep_for(std::chrono::milliseconds(100));
    std::lock_guard<std::mutex> lock1(mutex1);
    // 临界区代码
}

int main() {
    std::thread t1(threadA);
    std::thread t2(threadB);
    t1.join();
    t2.join();
    return 0;
}
解决方案

重新设计资源分配顺序,避免循环等待:

cpp 复制代码
#include <mutex>
#include <thread>
#include <iostream>

std::mutex mutex1, mutex2;

void acquire_locks(std::mutex& lock1, std::mutex& lock2) {
    if (&lock1 > &lock2) {
        std::lock_guard<std::mutex> lock(lock1);
        std::lock_guard<std::mutex> lock2(lock2);
    } else {
        std::lock_guard<std::mutex> lock(lock2);
        std::lock_guard<std::mutex> lock1(lock1);
    }
}

void thread_function() {
    acquire_locks(mutex1, mutex2);
    // 临界区代码
}

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

4. 锁嵌套(Lock Nesting)

问题描述

在一个锁的保护范围内申请另一个锁,导致锁顺序不一致。

cpp 复制代码
#include <mutex>
#include <thread>
#include <iostream>

std::mutex mutex1, mutex2;

void nested_locks() {
    std::lock_guard<std::mutex> lock1(mutex1);
    std::this_thread::sleep_for(std::chrono::milliseconds(100));
    std::lock_guard<std::mutex> lock2(mutex2);
    // 临界区代码
}

int main() {
    std::thread t(nested_locks);
    t.join();
    return 0;
}
解决方案

避免锁嵌套,确保所有锁以相同的顺序获取:

cpp 复制代码
#include <mutex>
#include <thread>
#include <iostream>

std::mutex mutex1, mutex2;

void acquire_locks(std::mutex& lock1, std::mutex& lock2) {
    if (&lock1 > &lock2) {
        std::lock_guard<std::mutex> lock(lock1);
        std::lock_guard<std::mutex> lock2(lock2);
    } else {
        std::lock_guard<std::mutex> lock(lock2);
        std::lock_guard<std::mutex> lock1(lock1);
    }
}

void thread_function() {
    acquire_locks(mutex1, mutex2);
    // 临界区代码
}

int main() {
    std::thread t(thread_function);
    t.join();
    return 0;
}
相关推荐
weixin-a153003083161 天前
python-装饰器
开发语言·python
我的xiaodoujiao1 天前
快速学习Python基础知识详细图文教程17--类型注解和断点调试
开发语言·python·学习·测试工具
ltl1 天前
向量库与图 RAG:HNSW、DiskANN 到 GraphRAG
linux
学代码的CJY1 天前
Linux 库制作与原理:静态库、动态库、ELF 与动态链接完全指南
linux·运维·服务器
leoZ2311 天前
AI 辅助开发的五道坎
开发语言·人工智能·视觉检测·bert·php·超分辨率重建·openvino
会周易的程序员1 天前
aiDgePLC — IEC61131-3 ST PLC 虚拟机调试与运行环境
c++·物联网·虚拟机·st·工业协议·iec61131·梯形图
程序员老陆1 天前
Qt的QThread::usleep和FFmpeg的libavutil模块的av_usleep哪个精度高一些?
开发语言·qt·ffmpeg·音视频
呱呱巨基1 天前
Linux 查找命令
linux·笔记·学习·查找命令
2601_963869951 天前
【计算机毕业设计】基于Java的相框定制系统的设计与实现
java·开发语言·课程设计
basketball6161 天前
软考中级网络工程师 第4章 无线通信网 备考总结
linux·服务器·网络·网络工程师·软考