【CPP】死锁产生、排查、避免

C++多线程死锁:成因、避免策略与调试技巧 在多线程编程中,死锁是当多个线程因争夺资源而陷入相互等待的僵局,导致程序无法继续执行的现象。其核心原理基于互斥、请求与保持、不剥夺和循环等待四个必要条件。理解并破坏这些条件对于构建健壮的并发系统至关重要,能显著提升程序的可靠性与可维护性。在实际的工程实践中,死锁问题常见于资源管理、任务调度等场景。通过采用固定锁顺序、利用C++标准库的std::scoped_lock等工具,可以有效规避风险。本文聚焦于C++环境,深入探讨了std::mutex、std::lock_guard等机制下的典型死锁场景与系统性解决 阅读详情

一、死锁产生

死锁是指两个或多个线程互相等待对方释放资源,导致程序无法继续执行的现象。在多线程编程中,死锁是一种常见且严重的并发问题。死锁产生必须要四个条件同时满足才会发生:

  • 互斥条件:某些资源只能由一个线程占用。
  • 占有且等待:线程已经占有至少一个资源,同时等待其他资源。
  • 不可剥夺:资源不能被强制剥夺,只能由持有线程主动释放。
  • 环路等待:多个线程形成环形等待链,导致死锁。

二、死锁排查

假如我们有如下代码需要排查死锁。

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

std::mutex mtx1;
std::mutex mtx2;

void thread_func1() {
    std::lock_guard<std::mutex> lock1(mtx1); // 锁定 mtx1
    std::this_thread::sleep_for(std::chrono::milliseconds(100)); // 模拟工作
    std::lock_guard<std::mutex> lock2(mtx2); // 尝试锁定 mtx2
}

void thread_func2() {
    std::lock_guard<std::mutex> lock1(mtx2); // 锁定 mtx2
    std::this_thread::sleep_for(std::chrono::milliseconds(100)); // 模拟工作
    std::lock_guard<std::mutex> lock2(mtx1); // 尝试锁定 mtx1
}

int main() {
    std::thread t1(thread_func1);
    std::thread t2(thread_func2);

    t1.join();
    t2.join();

    return 0;
}

由于主线程的存在,在后续的表述中t1 对应线程2,t2 对应线程3

1)Linux命令

通过Linux命令初步排查判断死锁的发生。

1. ps

查看进程状态:ps -T -p <pid> -o pid,tid,user,stat,cmd

  • -T:显示指定进程的所有线程
  • -p <pid>:指定进程的 PID
  • -o:自定义输出的列,后面可以指定字段列表,用逗号分隔。
Ubuntu ❯❯❯ ps -T -p 2311810 -o pid,tid,user,stat,cmd
    PID     TID USER     STAT CMD
2311810 2311810 Raizero+ Sl+  ./deadlock
2311810 2311811 Raizero+ Sl+  ./deadlock
2311810 2311812 Raizero+ Sl+  ./deadlock
  • 线程状态(STAT):所有的线程都处于 S(Sleeping)状态。S 表示线程在等待某些操作(如 I/O、资源等),并且处于可中断的睡眠状态。此时线程可能处于的正常状态,而不是死锁的直接标志。死锁线程可能处于 S 或 D 状态,需结合工具进一步分析。
2. top

实时监控线程和进程:top -H -p <pid>

  • -H:显示线程信息(Thread)
  • -p:指定进程的 PID(Process ID)
  • <pid>:可能发生死锁的进程pid
 进程号 USER      PR  NI    VIRT    RES    SHR    %CPU  %MEM     TIME+ COMMAND                                   
2292389 Raizero+  20   0   87992   2880   2880 S   0.0   0.0   0:00.00 deadlock                                  
2292390 Raizero+  20   0   87992   2880   2880 S   0.0   0.0   0:00.00 deadlock                                  
2292391 Raizero+  20   0   87992   2880   2880 S   0.0   0.0   0:00.00 deadlock     
  • 所有线程的 %CPU 和 %MEM 都是 0.0,说明它们没有占用 CPU 资源,也没有执行任何工作。
  • 线程正在处于某种等待状态,而没有消耗 CPU 时间。死锁中,线程通常会持续等待并且不会执行任何任务,可能会表现出这种行为。

2)工具

1. gdb

使用 gdb 附加到正在运行的进程:gdb -p <pid>

  • -p:表示附加到正在运行的进程
  • <pid>:目标进程的进程 ID
Ubuntu ❯❯❯ gdb -p 2301629
...
__futex_abstimed_wait_common64 (private=128, cancel=true, abstime=0x0, op=265, expected=2301630, futex_word=0x7c29d5a00910) at ./nptl/futex-internal.c:57
...

显示了一个关于 futex 的调用,futex 是一种用于线程同步的机制,通常与死锁或等待条件相关。这里的错误表明某个线程在等待某个 futex 锁,但 gdb 不能找到相关的源文件,因此它无法提供更多的调试信息。需要进一步调试:

  • 查看所有线程的堆栈:info threads

    (gdb) info threads
    ···
    Thread 0x7c29d62ac740 (LWP 2301629) "deadlock" 
    __futex_abstimed_wait_common64 (private=128, cancel=true, abstime=0x0, op=265, expected=2301630, futex_word=0x7c29d5a00910) 
    at ./nptl/futex-internal.c:57
    ···
    
    • 这表示线程 1 正在调用 futex 等待操作,可能是等待某个资源或锁的释放。
    ...
    Thread 0x7c29d5a00640 (LWP 2301630) "deadlock" 
    futex_wait (private=0, expected=2, futex_word=0x63974eebd1a0 <mtx2>) 
    at ../sysdeps/nptl/futex-internal.h:146
    ...
    
    • 线程 2 正在等待 mtx2 锁。
    ···
    Thread 0x7c29d5000640 (LWP 2301631) "deadlock" 
    futex_wait (private=0, expected=2, futex_word=0x63974eebd160 <mtx1>) 
    at ../sysdeps/nptl/futex-internal.h:146
    ···
    
    • 线程 3 正在等待 mtx1 锁。

    从这些信息可以推断出死锁的可能性。线程 2 正在等待 mtx2 锁,而线程 3 正在等待 mtx1 锁。考虑到这两个锁的互相依赖性,很可能发生了一个循环依赖(死锁):

    • 线程 1 可能持有 mtx1 或 mtx2 锁,并且等待另一个锁。
    • 线程 2 等待 mtx2,而线程 3 等待 mtx1,它们互相等待对方释放锁,导致无法继续执行。
  • 检查线程堆栈:thread <thread> bt

    (gdb) thread 1 bt
    [Switching to thread 1 (Thread 0x7c29d62ac740 (LWP 2301629))]
    #0  __futex_abstimed_wait_common64 (private=128, cancel=true, abstime=0x0, op=265, expected=2301630, 
        futex_word=0x7c29d5a00910) at ./nptl/futex-internal.c:57
    57      in ./nptl/futex-internal.c
    
    (gdb) thread 2 bt
    [Switching to thread 2 (Thread 0x7c29d5a00640 (LWP 2301630))]
    #0  futex_wait (private=0, expected=2, futex_word=0x63974eebd1a0 <mtx2>) at ../sysdeps/nptl/futex-internal.h:146
    
    (gdb) thread 3 bt
    [Switching to thread 3 (Thread 0x7c29d5000640 (LWP 2301631))]
    #0  futex_wait (private=0, expected=2, futex_word=0x63974eebd160 <mtx1>) at ../sysdeps/nptl/futex-internal.h:146
    
    • 线程 1 正在执行 __futex_abstimed_wait_common64,这表示它在等待某个资源或锁释放。
    • 线程 2 和 线程 3 都在执行 futex_wait,分别等待 mtx2 和 mtx1 锁的释放。

这些信息表明,线程 2 和线程 3 正在等待彼此持有的锁,这可能是死锁的典型表现。死锁的发生通常是由于线程形成了循环等待的依赖关系:

  • 线程 2 等待 mtx2 锁,而 mtx2 锁由线程 3 持有。
  • 线程 3 等待 mtx1 锁,而 mtx1 锁由线程 2 持有。
2. valgrind

使用其线程分析工具 Helgrind 检测死锁:valgrind --tool=helgrind <process_name>

Ubuntu ❯❯❯ valgrind --tool=helgrind ./a.out
  • 锁的首次获取路径

    • mtx1 (0x10E160) 首次被线程2获取:

      ==2305017==  Lock at 0x10E160 was first observed
      ==2305017==    by 0x109365: thread_func1() (deadlock.cc:9)
      

      对应 thread_func1() 中第9行的 std::lock_guard<std::mutex> 锁定 mtx1。

    • mtx2 (0x10E1A0) 首次被线程3获取:

      ==2305017==  Lock at 0x10E1A0 was first observed
      ==2305017==    by 0x10946C: thread_func2() (deadlock.cc:17)
      

      对应 thread_func2() 中第17行的 std::lock_guard<std::mutex> 锁定 mtx2。

  • 线程终止时的锁持有状态

    • 线程2(持有 mtx1)尝试获取 mtx2 时被阻塞:

      ==2305017== Thread #2: Exiting thread still holds 1 lock
      ==2305017==    by 0x1093BA: thread_func1() (deadlock.cc:12)
      

      对应 thread_func1() 中第12行尝试获取 mtx2 时卡住(例如 std::lock_guard<std::mutex> lock2(mtx2))。

    • 线程3(持有 mtx2)尝试获取 mtx1 时被阻塞:

      ==2305017== Thread #3: Exiting thread still holds 1 lock
      ==2305017==    by 0x1094C1: thread_func2() (deadlock.cc:20)
      

      对应 thread_func2() 中第20行尝试获取 mtx1 时卡住(例如 std::lock_guard<std::mutex> lock1(mtx1))。

根据以上信息说明两个线程在终止前未能释放已获得的锁,导致其他线程无法获取这些锁。Thread #2(假设对应代码中的线程1)在 thread_func1() 中先锁定 mtx1,然后尝试获取 mtx2。Thread #3(假设对应代码中的线程2)在 thread_func2() 中先锁定 mtx2,然后尝试获取 mtx1。这种交叉锁定形成了循环等待,是死锁的典型条件。

3. 日志

在代码中加入日志记录,标注线程锁定和解锁的时间点、资源ID等信息,以分析死锁发生的位置。我们对于死锁代码加入如下日志:

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

std::mutex mtx1;
std::mutex mtx2;

void thread_func1() {
    std::cout << "Thread 1: Trying to lock mtx1\n";
    std::lock_guard<std::mutex> lock1(mtx1); // 锁定 mtx1
    std::cout << "Thread 1: Acquired mtx1\n";
    std::this_thread::sleep_for(std::chrono::milliseconds(100)); // 模拟工作
    std::cout << "Thread 1: Trying to lock mtx2\n";
    std::lock_guard<std::mutex> lock2(mtx2); // 尝试锁定 mtx2
    std::cout << "Thread 1: Acquired mtx2 and completed\n";
}

void thread_func2() {
    std::cout << "Thread 2: Trying to lock mtx2\n";
    std::lock_guard<std::mutex> lock1(mtx2); // 锁定 mtx2
    std::cout << "Thread 2: Acquired mtx2\n";
    std::this_thread::sleep_for(std::chrono::milliseconds(100)); // 模拟工作
    std::cout << "Thread 2: Trying to lock mtx1\n";
    std::lock_guard<std::mutex> lock2(mtx1); // 尝试锁定 mtx1
    std::cout << "Thread 2: Acquired mtx1 and completed\n";
}

int main() {
    std::thread t1(thread_func1);
    std::thread t2(thread_func2);
    
    t1.join();
    t2.join();

    return 0;
}
  • 线程 1 停止在尝试锁定 mtx2:此时 mtx1 被线程 1 持有,而 mtx2 被线程 2 持有,两个线程互相等待解锁。

    Thread 2: Trying to lock mtx2
    Thread 2: Acquired mtx2
    Thread 2: Trying to lock mtx1
    Thread 1: Trying to lock mtx1
    Thread 1: Acquired mtx1
    Thread 1: Trying to lock mtx2
    
  • 线程 2 停止在尝试锁定 mtx1:情况相同,线程 1 和线程 2 分别持有一个锁,互相等待。

    Thread 1: Trying to lock mtx1
    Thread 1: Acquired mtx1
    Thread 1: Trying to lock mtx2
    Thread 2: Trying to lock mtx2
    Thread 2: Acquired mtx2
    Thread 2: Trying to lock mtx1
    

通过分析日志,如果发现某些线程的锁定日志输出到一半停止,后续锁未能成功获取且程序未继续运行,则可以推测程序可能发生了死锁。

三、死锁预防与解决

实际上来讲死锁几乎无法避免,我们只能说尽量避免并在死锁发生时利用各种手段解决。

1. 使用C++ RAII,避免忘记解锁造成的死锁

利用RAII(Resource Acquisition Is Initialization)机制,通过对象的构造和析构自动管理锁的生命周期,确保异常安全。

  • std::lock_guard

    std::mutex mtx;
    {
        std::lock_guard<std::mutex> lock(mtx); // 自动加锁
        // 临界区操作
    } // 离开作用域自动解锁
    
  • std::unique_lock

    std::mutex mtx;
    try {
        std::unique_lock<std::mutex> lock(mtx);
        // 可能抛出异常的操作
    } catch (...) {
        // 锁会在栈展开时自动释放
    }
    

优势:

  • 避免因忘记调用unlock()导致的死锁。
  • 异常安全:即使临界区代码抛出异常,析构时仍会释放锁。
2. 使用c++ std::lock锁,来避免多次加锁顺序导致的死锁

std::lock(mtx1, mtx2, ...)原子性地同时锁定多个互斥量,避免因不同线程加锁顺序不一致导致的死锁。

std::mutex mtx1, mtx2;
{
    std::unique_lock<std::mutex> lock1(mtx1, std::defer_lock);
    std::unique_lock<std::mutex> lock2(mtx2, std::defer_lock);
    std::lock(lock1, lock2); // 原子性同时加锁
    // 操作共享资源
} // 自动解锁

关键点:

  • 结合std::adopt_lock标记表示锁已被获取,避免重复加锁。
  • 必须使用std::unique_lock(std::lock_guard不支持手动管理)。
3. 递归锁解决单线程重复加锁问题

使用std::recursive_mutex允许同一线程多次加锁。

std::recursive_mutex rmtx;
{
    std::lock_guard<std::recursive_mutex> lock1(rmtx); // 第一次加锁
    {
        std::lock_guard<std::recursive_mutex> lock2(rmtx); // 同一线程内再次加锁
    }
}

关键点:

  • 递归锁性能低于普通锁,且需确保lock()与unlock()次数匹配。
  • 优先考虑重构代码逻辑,避免嵌套加锁。
4. 避免嵌套锁

减小临界区范围仅在必须访问共享资源时加锁,或者将临界区代码提取为独立函数,减少锁的嵌套层次。

void critical_operation() {
    std::lock_guard<std::mutex> lock(mtx);
    // 仅包含必须同步的操作
}

void outer_function() {
    // 非临界区代码
    critical_operation(); // 调用独立加锁的函数
}
5. 使用锁顺序

全局约定所有线程以相同顺序获取锁,破坏循环等待条件。

// 总是先锁地址最小的
void lock_in_order(std::mutex& mtx1, std::mutex& mtx2) {
    if (&mtx1 < &mtx2) {
        std::lock_guard<std::mutex> lock1(mtx1);
        std::lock_guard<std::mutex> lock2(mtx2);
    } else {
        std::lock_guard<std::mutex> lock2(mtx2);
        std::lock_guard<std::mutex> lock1(mtx1);
    }
}

按地址排序的锁顺序策略可能因平台或编译器差异失效。

6. 锁超时

使用try_lock_for()或try_lock_until()设置超时。

std::timed_mutex tmtx;
if (tmtx.try_lock_for(std::chrono::milliseconds(100))) {
    // 成功获取锁
    tmtx.unlock();
} else {
    // 超时处理
}
7. 原子操作

使用原子变量彻底避免锁的使用,消除死锁风险。

std::atomic<int> counter{0};
counter.fetch_add(1, std::memory_order_relaxed);
8. 检测并恢复
  • 动态检测:记录锁获取顺序,检测循环等待。
  • 超时回滚:设定超时时间,超时后释放资源并重试。
9. 数据分区

通过分区技术避免不同线程同时访问同一个资源,消除死锁可能性。

  • 将数据划分为多个独立的部分,分配给不同的线程。
  • 常用于多线程处理大规模数据的场景。
高薪程序员&面试题精讲系列72之死锁产生的原因及解决办法,如何定位死锁产生的位置? 一. 面试题及剖析 1. 今日面试题 如何保证线程的安全? 如何保证线程的有序性? 线程死锁是怎么产生的? 如何解决线程死锁? 如果生产环境的项目产生了死锁如何定位? 2. 题目剖析 在前两篇文章中,壹哥给大家讲解了线程安全问题的由来,JMM线程模型,以及保证线程安全的2种手段--原子性、可见性,如果你还没看过壹哥的前2篇文章,可以移步到前文: 高薪程序员&面试题精讲系列70之如何保证线程安全?你有没有遇到过线程死锁问题 高薪程序员&面试题精讲系列71之你熟悉vola 阅读详情

相关推荐

【面试题】MySQL索引相关的面试题(红黑树,hash,B树,B+树)

自己整理了几个面试题分享给大家 问题1:红黑树为什么那样设计? 首先聊一下二叉搜索树,主要特点是左节点比根节点小,右节点比根节点大,并且左右子树都是二叉搜索树。缺点是在极端情况下,比如插入都是有序的,就会出现退化的情况有序序列树退化成链表。 二叉搜索树 退化成链表的二叉搜索树 此时,要想让树的节点平均分布就需要平衡树了,红黑树就是平衡树的一种(平衡二叉搜索树)。然后,一棵树的查询性能取决...

Mr_黑_ 的博客 4042

c++ 死锁检测与内存泄露

通过hook函数从写malloc/free函数,每次malloc都回创建一个.mem文件,free会将申请内存时创建的文件删除,当mem文件夹下存在文件时,说明会有内存泄露,查看文件中内存可以查询到具体在哪里发生内存泄露。valgrind是一款内存错误检测工具,而helgrind是valgrind工具集成的一款工具,用于检测多线程程序中的竞争条件和死锁;helgrind通过获取模拟死锁的获取和释放来检测线程之间是否存在非法的资源访问序列,从而查找可能出现死锁的编程错误。超时后释放已经获取的资;

xiaofeilongyu的博客 2092

突发E层(Es层):短波通信中的“意外惊喜”与“隐形杀手”全解析

本文深入解析了突发E层(Es层)在短波通信中的双重作用,既可能带来超远距离通信的“意外惊喜”,也可能成为通信链路的“隐形杀手”。通过分析Es层的形成机制、时空分布规律及实战应用技巧,帮助通信爱好者与专业人员更好地利用或应对这一电离层现象,提升短波通信的可靠性与效率。

weixin_30443813的博客 822

C++如何判断一个程序是 死锁 还是 死循环,如何进行问题定位与分析

目录 一、初步诊断: 1、死循环: 2、死锁: 二、进一步定位分析: 1、初步诊断为 死循环 时,可转存为 Dump 进行分析 2、死锁 情况就比较复杂: 三、、代码与图示: 1、死循环: 2、死锁: 一、初步诊断: 通过 ‘任务管理器’ 查看软件的状态 与 CPU 使用情况 1、死循环: 软件状态:未响应 CPU:一直保持非0,处于活跃状态 原理: 如果主线程出现死循环,那么windows将不能从消息队列中取出消息,并进行处理,所以出现卡死现象。为了验证是这个原因导致

LearnLHC的博客 8811

一文学会Cadence Sigrity PDN仿真——硬件新手小白都能看懂的保姆级教程

电源完整性的仿真,实际上是在仿真以及优化系统中的等效串联电阻。知道了仿真以及优化的目标之后,接下来就是要弄明白这个串联电阻从哪儿来以及怎么优化。整个系统中的串联电阻实际上由三部分组成:没有相位的阻抗,有相位的容抗和感抗,得益于相位,在某个特定的频点,容抗和感抗会大小相等,相位相反而相互抵消,这时候整个系统中就剩下了阻抗,所以整个系统的串联电阻达到了一个最低值,这种现象就是----谐振。当系统处于谐振点时候,整个系统会有一个最小的串联电阻,所以第一个优化电阻的手段就是让谐振来的更频繁一点。

学习帮的博客 2万+

PTrade数据交互全流程详解:从本地文件上传到定时导出交易数据

本文详细解析了PTrade量化交易平台的数据交互全流程,涵盖从本地文件自动上传交易指令到定时导出成交数据的完整链路。通过文件媒介实现本地策略与云端实盘的安全、稳定对接,并提供了构建自动化、稳健数据流水线的实战配置方案与代码示例,助力量化工作流平滑过渡至实盘。

gg901的博客 882

深度讲解futex问答(上)

futex是Fast Userspace muTEX的缩写,该机制是由Rusty Russell、Hubertus Franke和Mathew Kirkwood在2.5.7版本的内核中引入,虽然名字中有互斥锁(mutex)的含义,但实际它是一种用于用户空间应用程序的通用同步工具(基于futex可以在userspace实现互斥锁、读写锁、condition variable等同步机制)。Futex组成包括:内核空间的等待队列。

youzhangjing_的博客 3571

机场数据治理系列介绍(1):机场行业数据中台中的数据管理顶层设计方案

民航机场行业的数据中台中,有关数据管理顶层设计方案需要结合机场行业的业务特点和技术需求进行具体的设计,今日我们简要考量设计提供一个参考方案:

机场信息系统研究员的专栏 1604

C++死锁

线程快照是当前java虚拟机内每一条线程正在执行的方法堆栈的集合,生成线程快照的主要目的是定位线程出现长时间停顿的原因,如线程间死锁、死循环、请求外部资源导致的长时间等待等。它用于连接正在运行的本地或者远程的JVM,对运行在Java应用程序的资源消耗和性能进行监控,并画出大量的图表,提供强大的可视化界面。该算法的核心思想是将系统中的资源分为多个类别,并且在分配资源时使用贪心的策略,确保可以满足所有进程的需求,并且不会造成死锁或资源耗尽等问题。去破坏产生死锁的四个必要条件中的一个或几个来预防死锁的产生。

qq_45780653的博客 2456

达梦数据库导入报错:[警告]服务器与文件内数据的 CASE_SENSITIVE 参数不匹配,成功终止导入, 但出现警告dimp V8,本地编码:PG_GBK, 导入文件编码:PG_UTF8

达梦数据库管理系统的最新版本是8.0版本,简称DM8。DM8采用全新的体系架构,在保证大型通用的基础上,针对可靠性、高性能、海量数据处理和安全性做了大量的研发和改进工作,极大提升了达梦数据库产品的性能、可靠性、可扩展性,能同时兼顾OLTP和OLAP请求,从根本上提升了DM8产品的品质。达梦数据库管理系统是达梦公司推出的具有完全自主知识产权的高性能数据库管理系统,简称DM。[警告]服务器与文件内数据的 CASE_SENSITIVE 参数不匹配,成功终止导入, 但出现警告。4.无视警告,输入y,回车。

十三月的博客 1万+

Sigrity System Explorer Transient Analysis模式进行瞬态仿真分析操作指导-差分信号

Sigrity System Explorer Transient Analysis模式可以用于瞬态仿真分析,通过搭建简易拓扑用于前仿真分析通道的时域性能,下面搭建一个简易的差分拓扑进行说明,以下图为例,准备好发送接收端的IBIS模型, (ibis_se.ibs,本例发送接收端都使用相同的IBIS模型),以及传输线的S参数模型(welement_se.sp)最上方的图形界面是传输线的模型,本例是一个上下都有参考平面的带状线,右侧的梯形是蚀刻角度,根据W1和W2以及铜厚来确定。

weixin_54787054的博客 440

c++中如何排查死锁

判断是否死锁:程序是否卡住且无响应定位线程:使用 gdb / 日志 / helgrind 等定位线程卡在哪个锁上分析锁顺序与资源使用图,确认是否有循环等待帮你分析具体死锁代码段提供多线程死锁的调试脚本或 gdb 指令写个多线程模拟死锁 + 排查流程的例子需要哪种帮助?

JC的博客 807

特殊通信领域场景应用:基于Simulink的数字预失真(DPD)算法仿真建模示例

增益压缩:高功率输入时输出信号的增益下降。相位失真:输入信号的相位随功率变化而改变。带外干扰:非线性失真会引入额外的频谱分量,影响邻道信号。多项式模型:用多项式拟合功率放大器的非线性特性。查找表(LUT):通过离线训练生成预失真映射表。自适应算法:实时调整预失真参数以动态补偿失真。发送端:生成随机比特流并调制为射频信号。预失真模块:对输入信号进行预失真处理。功率放大器模块:模拟非线性失真。接收端:解调信号并评估误码率(BER)。

xiaoheshang_123的博客 272

死锁是什么?如何避免?如何排查?为什么这样排查 详细总结

1.定位线程+代码行 需要找到哪行代码发生了死锁 因此需要找到出问题的线程thread 1切换线程bt查看线程的堆栈调用)2.全部线程 那么就需要先查看所有线程的堆栈调用情况3.跟踪进程 使用attach跟踪进程sudogbd进程号确定其中线程具体工作4.确定是否死锁查看具体进程内存占用 确定是否发生了死锁5.查看进程状态 确定进程号ps。

weixin_57672347的博客 2585

华为的C语言编程规范.pdf

华为技术有限公司内部技术规范。本规范制定了编写C语言程序的基本原则、规则和建议。从代码的清晰、简洁、可测试、安全、程序效率、可移植各个方面对C语言编程作出了具体指导。

蓝牙模块HM-10手册

蓝牙模块HM-10手册,该手册对蓝牙模块HM-10进行了详细的介绍和使用方法以及一些AT指令。

C++死锁彻底攻克:从原理剖析到工程级避免与排查

并发编程中,死锁是每个开发者绕不开的难题,尤其在C++多线程场景下,锁使用不当极易引发线程永久阻塞。理解死锁的四个必要条件——互斥、持有并等待、不可剥夺、循环等待,是系统性解决问题的基础。而工程实践上,通过统一加锁顺序、控制锁粒度、借助RAII封装以及C++17的std::scoped_lock,可以高效打破循环等待,从源头规避风险。当线上出现卡死时,利用gdb抓取线程栈、借助Helgrind或ThreadSanitizer等工具自动检测,能快速定位问题根因。本文从原理到实践,结合真实案例与速查表,为C++

weixin_32075843的博客 67

android 蓝牙通讯demo

android 下蓝牙通讯demo,实现了发现蓝牙,使能蓝牙,通过蓝牙发送消息。

c++并发编程,多线程问题,死锁

c++并发编程,多线程问题,死锁 并发编程中的多线程编程中的经典问题: 死锁 产生方式和规避方法。 死锁: 1.两个线程A,B访问共享数据Data,Data被两个互斥量Amutex,Bmutex锁着; 2.线程A访问Data时,先拿到Amutex,后拿到Bmutex; 3.线程B访问Data时,先拿到Bmutex,后拿到Amutex; 4.在运行时的某个时刻,线程A拿到了Amutex,线程B拿到了Bmutex; 5.A等B解锁Bmutex才能继续,B等A解锁Amutex才能继续; 6.A,B线程均进入等待对

ganfanren00001的博客 318

温度PID控制PLC程序

温度PID稳定控制程序,适用于欧姆龙PLC,对其他PLC也具有很大参考价值

[C++] --- 死锁

只要四个条件同时满足,就可能发生死锁。我们举个例子来描述,如果此时有一个线程A,按照先锁a再获得锁b的的顺序获得锁,而在此同时又有另外一个线程B,按照先锁b再锁a的顺序获得锁。

M2嵌入式 1387

图解Java中的锁:什么是死锁?怎么排查死锁?怎么避免死锁?

在面试过程中,死锁也是高频的考点,因为如果线上环境很多发生了死锁,那真的出大事了。 这次,我们就来系统地聊聊死锁的问题。 死锁的概念; 模拟死锁问题的产生; 利用工具排查死锁问题; 避免死锁问题的发生; 死锁的概念 在多线程编程中,我们为了防止多线程竞争共享资源而导致数据错乱,都会在操作共享资源之前加上互斥锁,只有成功获得到锁的线程,才能操作共享资源,获取不到锁的线程就只能等待,直到锁被释放。 那么,当两个线程为了保护两个不同的共享资源而使用了两个互斥锁,那么这两个互斥锁应用不当的时候,可能会

m0_58008803的博客 292

【C/C++】死锁的四大条件与预防策略详解

死锁的四大条件与预防策略详解

YZJincsdn的博客 1002

C++之,我是如何解决多线程死锁问题的

在C++编程的工作实践中,多线程编程能极大地提升程序的运行效率,但同时也引入了死锁这个令人头疼的问题。我在参与一个资源调度系统开发时,就遭遇了死锁困境,经过一番摸索与实践,终于找到了解决办法,现在就和大家分享这段经历。

wj_rdk的博客 1488

死锁深度解析:原理、场景、检测与解决方案(C++实践篇)

本文系统讲解了C++多线程编程中的死锁问题。首先明确定义了死锁及其四个必要条件(互斥、请求保持、不可剥夺和循环等待),分析了常见死锁场景如锁顺序不一致、递归锁不当使用等。然后介绍了死锁检测方法,包括资源分配图法、命令行工具和日志监控。重点阐述了三种解决策略:预防死锁(破坏必要条件)、避免死锁(银行家算法)和解除死锁(终止线程或资源剥夺)。最后给出了C++并发编程中的最佳实践建议,并区分了死锁与活锁、饥饿的区别。文章提供了可落地的解决方案,帮助开发者彻底解决死锁问题。

2402_83493359的博客 924

一不小心死锁了怎么办?

一不小心死锁了怎么办死锁基础概念什么是死锁示例代码使用jdk工具(windows系统)排查死锁代码使用jstack查看堆栈信息产生死锁的条件互斥条件占有且等待不可抢占循环等待如何避免死锁破环占有且等待条件破环不可抢占条件破坏循环等待条件总结 死锁基础概念 什么是死锁 死锁是指两个或两个以上的线程在执行过程中,由于竞争资源或者由于彼此通信而造成的一种阻塞的现象,若无外力作用,它们都将无法推进下去。...

未曾遗忘的博客 186

C++死锁全解析:从产生条件到调试实战与规避策略

在多线程编程中,互斥锁是保护共享数据的常用手段,但锁的不当使用容易引发线程互相等待的僵局,即死锁。理解死锁的四个必要条件——互斥、持有并等待、不可剥夺、循环等待,是定位问题的基石。C++并发开发中,通过锁顺序一致化、使用std::scoped_lock原子获取多锁、以及引入锁超时机制,能够有效预防死锁。同时,借助gdb的线程栈分析和ThreadSanitizer的锁序倒置检测,开发者可以快速复现并定位线上卡死问题。本文结合工程实践,从死锁原理讲到现代C++并发工具,再到典型场景的排查实录,为C++开发者提供

weixin_34268753的博客 304

C/C++内存泄漏与死锁排查:从原理到实战的完整防御指南

在C/C++系统开发中,内存管理和多线程同步是两大核心基础。内存泄漏指程序动态申请的内存未能正确释放,如同慢性失血,长期运行将耗尽资源导致崩溃;而死锁则是多线程环境中因循环等待资源而导致的程序永久阻塞,严重影响系统可用性。理解其底层原理,对于构建高可靠、高性能的软件至关重要。通过掌握RAII(资源获取即初始化)、智能指针等现代C++范式,可以从编码源头杜绝多数内存问题;而遵循严格的锁顺序、使用死锁避免算法,则是预防并发缺陷的关键。这些技术的价值在于保障服务的长期稳定运行,尤其适用于服务器、嵌入式系统、游戏引

weixin_34232744的博客 534

记一次死锁问题的排查

最近遇到了一个死锁问题, 记录一下排查的过程. SQL Server中的死锁是DBA们经常会遇到的问题.  常有人混淆了死锁和阻塞, 其实他们的区别还是很明显的.  阻塞的一般原因可能是进程在等待事务提交,或者某个操作的完成, 是资源上的冲突, 只要等待足够长的时间,是一定可以解决的;  但是死锁是逻辑上的冲突, 也就是说无论等待多长的时间, 更换多么强大的硬件, 都是无法解决死锁的

lucky7_2000的专栏 1089

C++多线程死锁排查实战:从原理到GDB调试全解析

在多线程编程中,死锁是并发控制面临的经典挑战,它发生在多个线程因循环等待资源而陷入永久阻塞。其核心原理涉及互斥、持有并等待、不可剥夺和循环等待四个必要条件。在C++工程实践中,标准库提供的`std::mutex`、`std::lock_guard`和`std::unique_lock`等同步原语是实现互斥访问的关键工具,但使用不当极易引发死锁,严重影响程序健壮性。理解锁的粒度与持有时间对预防死锁至关重要。当程序出现无响应时,开发者需要掌握有效的排查手段。利用GDB动态调试工具,可以附加到运行进程,检查线程状

weixin_32821533的博客 245
上一篇: 【形象解析】ptmalloc、tcmalloc与jemalloc对比
Raizeroko
博客等级 码龄6年 1913粉丝 27原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值