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

C++多线程死锁检测方法 基本思路:在加锁时,通过有向图来对锁进行记录,判断图结构是否形成了闭环,形成闭环则出现死锁。 阅读详情
AI摘要

本文介绍了如何通过任务管理器初步诊断程序中的死锁和死循环问题,进一步提供了使用WinDbg工具进行深入分析的方法,并探讨了两种创建转储文件(dump)的方式,以便于故障排查。

目录

一、初步诊断:

1、死循环:

2、死锁:

二、进一步定位分析:

1、初步诊断为 死循环 时,可转存为 Dump 进行分析

2、死锁 情况就比较复杂:

3、死锁的定位和分析

4、如何转储 dump [自己监控异常; 另起进程 监控异常]

三、、代码与图示:

1、死循环:

2、死锁:


一、初步诊断:

通过 ‘任务管理器’ 查看软件的状态 与 CPU 使用情况

1、死循环:

软件状态:未响应

CPU:一直保持非0,处于活跃状态

原理:

如果主线程出现死循环,那么windows将不能从消息队列中取出消息,并进行处理,所以出现卡死现象。为了验证是这个原因导致界面卡死,打开任务管理器,如果该进程的cpu使用率一直保持非零,比如一直保持在 12%,那么界面卡死的原因是主线程死循环了。

2、死锁:

软件状态:正在运行

CPU:进程的 cpu 使用率一般是0

原理:

如果主线程由于跟其他的线程由于争夺资源或者锁,出现了死锁,那么主线程会一直等待资源或者锁,导致主线程不能继续往下执行,分发和处理消息,所以出现卡死

 

二、进一步定位分析:

1、初步诊断为 死循环 时,可转存为 Dump 进行分析

 

2、死锁 情况就比较复杂:

--- 使用 “任务管理器” 来检测一个程序是否陷入死锁

--- 打开 【任务管理器 - 详细信息 - 分析等待链】

--- 分析结果如下,可以看到当前测试程序处于死锁状态

--- 最后,对其进行【创建转储文件】转换为dump,再通过WinDbg对dump进行分析

3、死锁的定位和分析

如果死锁的程序刚好在我们自己的开发机器上,那么使用 WinDbg 的 Attach To A Proccess 功能将死锁程序直接附加到 WinDbg 中进行分析;

如果不在我们的机器上,可以通过 Windows 的 资源管理器 对进行进行 创建转储文件 转换为 dump(注意32位和64位的区别),再通过 WinDbg 对 dump进行分析。

为了方便,我们直接以 Attach 方式讲解。


     Attach 程序后,输入 !locks 命令查看锁的状态:

总共有两个锁cs1(012e4394)和cs2(012e437c),这两个锁的LockCount(表示还有多少个线程在等待这个临界区)都为1,说明这两个锁都处于等待状态。

     再输入~*kb查看一下当前各个线程的堆栈:

线程2534和线程1920都处于等待状态,线程2534等待锁012e437c,线程1920等待锁012e4394。

再结合上面的锁信息可以知道,锁012e4394被线程2534拥有,锁012e437c被线程1920拥有,所以这两个线程陷入了互相等待的死锁中。

等待锁的源码也直接定位到了,问题解决。

4、如何转储 dump [自己监控异常; 另起进程 监控异常]

A>、自己监控异常

MS 为我们提供了一个dbghelp.dll 的动态库

通过其提供的 MiniDumpWriteDump方法,我们可以进行dump的转储。

什么时候转储 dump 呢?

这里来介绍一下SetUnhandledExceptionFilter这个函数,当异常没有处理的时候,系统就会调用 SetUnhandledExceptionFilter 所设置异常处理函数,通过传入的回调函数来进行一些处理。

那么这个时候,我们就可以在回调函数中对当前程序的进程信息转储dump了。

缺陷:

这种方式有一些无能为力的时候,如果程序自身出现了无响应,整个进程卡死了,或者是程序的主线程中出现了死循环,以及程序在运行时闪退了

这些时候,程序自身是很难处理所出现的异常的,或者是根本没来得及处理

解决方法:另起进程来监控异常

B>、另起进程 监控异常

如果使用一个另外的程序来监测一个指定的程序,在其出现异常的时候,做一些后续的处理,那么首先面临的两个问题是:

问题一:用于监测的程序如何知道被监测的程序出现异常了;
问题二:当被监测的程序出现异常之后该如何处理。

问题一的解决方法:

Win32 有两个 API 函数可以帮助我们解决问题一,它们分别是 IsHungThread 和 IsHungAppWindow

它们可以根据所传入的进程句柄,来判断当前的进程是否处于正常响应的状态。

当被监测的程序出现了非正常响应,且满足一定的条件之后,我们可以认为它是出现了异常了,或者说不是一个理想的状态下了。

问题二的解决方法:

处理的目标同样是提示用户程序出现了异常,同时生成dump文件

MS为我们提供的另外一个工具:procdump,这个工具可以通过命令行来调用,比如对指定的进程进行dump转储,可以使用以下命令:

-ma 是转储参数,表示是以什么模式来进行转储。 

ma 是全量转储,即将所有进程相关的信息都进行转储。 

mp 是只转储有用的信息。具体介绍可以参考msdn介绍文档。 

8978 是对应进程的进程id。 

Test.dmp 是转储后dump文件的名称。

所以当我们知道被监测的程序出现异常之后,可以通过在程序中调用这个工具来对其进行dump的转储。

详情请查看: https://rdc.hundsun.com/portal/article/dump-607.html

扩展阅读:https://www.cnblogs.com/xybaby/p/8025435.html

三、、代码与图示:

1、死循环:

while (1){}

2、死锁:

#include <windows.h>
#include <iostream>
#include <thread>
#include <string>
#include <mutex>
#include <fstream>
using namespace std;

CRITICAL_SECTION cs1;
CRITICAL_SECTION cs2;

DWORD WINAPI Thread1(LPVOID lpParameter);
DWORD WINAPI Thread2(LPVOID lpParameter);

int main(int argc, TCHAR* argv[], TCHAR* envp[]){
	//初始化关键代码段
	InitializeCriticalSection(&cs1);
	InitializeCriticalSection(&cs2);
	//创建线程
	HANDLE hThread1 = CreateThread(NULL, 0, Thread1, NULL, 0, NULL);
	HANDLE hThread2 = CreateThread(NULL, 0, Thread2, NULL, 0, NULL);
	//等待线程结束
	WaitForSingleObject(hThread1, INFINITE);
	WaitForSingleObject(hThread2, INFINITE);
	Sleep(2000);
	//关闭线程句柄
	CloseHandle(hThread1);
	CloseHandle(hThread2);
	//释放关键代码段
	DeleteCriticalSection(&cs1);
	DeleteCriticalSection(&cs2);
	return 0;
}

DWORD WINAPI Thread1(LPVOID lpParameter){
	for (int i = 0; i < 10; i++){
    	EnterCriticalSection(&cs1);
		Sleep(500);
		EnterCriticalSection(&cs2);

		std::cout << "Thread1" << std::endl;

		LeaveCriticalSection(&cs2);
		LeaveCriticalSection(&cs1);
	}
	return 1;
}

DWORD WINAPI Thread2(LPVOID lpParameter){
	for (int i = 0; i < 10; i++){
		EnterCriticalSection(&cs2);
		Sleep(500);
		EnterCriticalSection(&cs1);

		std::cout << "Thread2" << std::endl;

		LeaveCriticalSection(&cs1);
		LeaveCriticalSection(&cs2);
	}
	return 1;
}

 

 

基于eBPF的procstat软件定位软件死锁 procstat是一款基于eBPF的监控工具软件,运行在Linux平台,主要用于跟踪目标程序的运行状态,并报告异常指标,是分析程序性能问题的一大利器。同时,procstat也可用于检测和定位C/C++多线程程序中的死锁问题。 阅读详情

相关推荐

VS2019 C++程序卡死诊断:从死循环到死锁的实战调试指南

在C++程序开发中,程序运行卡死是常见的调试难题,通常表现为界面无响应或CPU占用率异常。其背后原理往往涉及线程管理、资源调度或同步机制失效,例如线程陷入死循环、发生死锁或存在内存泄漏。掌握高效的诊断技术对于保障软件稳定性和性能至关重要。通过使用集成开发环境(IDE)内置的性能剖析工具和调试器,开发者可以深入分析程序运行时状态,精准定位问题根源。这种工程实践方法广泛应用于桌面应用、后台服务等需要高可靠性的场景。本文聚焦于Visual Studio 2019环境,详细解读如何利用其并行堆栈窗口和性能探查器等核

weixin_30247307的博客 414

怎样排查多线程死锁问题?

在使用多线程进行开发,大概率会遇到死锁问题。如何排查死锁问题,也变得非常重要。 第一步,我们可以通过pstack 捕获当前程序运行栈的信息,多次捕获比较,就能找到死锁的地方。 接下来可以通过分析代码,如果比较简单,确定是四个必要条件(互斥、占有且等待、不可抢占、循环等待)其中之一,打破即可。如果无法定位,代码看不出什么问题,就要进行调试。 第二步,当发生死锁,gdb attach 进程,info thread 查看线程, thread N 切换线程,查找所等待的互斥量,是被那个线程占用,一步一步排查。

不才的专栏 2766

VCS仿真Hang死排查实战:loopdetect与pstack组合定位死锁与死循环

在数字前端验证中,仿真Hang死是常见且棘手的问题,通常表现为进程停滞、CPU占用异常。其核心原理是进程执行停滞,可能由死循环、事件等待死锁或fork/join结构卡住引起。利用VCS的loopdetect机制和Linux的pstack工具,可以快速定位停滞进程和调用栈,显著提升调试效率。这些技术广泛应用于芯片验证、EDA仿真等场景,帮助工程师从被动等待转向主动诊断。本文深入解析loopdetect编译选项与pstack抓栈方法,结合典型Hang死场景,提供一套完整的排查链路和编码习惯,助力验证工程师高效解

weixin_30861459的博客 290

死锁及死锁检测

死锁检测分析及组件源码

djh的博客 6597

理解C++的死锁问题

在并发编程中,死锁是一个常见且棘手的问题。当两个或更多的线程永久地互相等待对方释放资源时,就会发生死锁。这种情况下,没有线程能够继续执行,因为每个线程都在等待其他线程释放资源。在这篇文章中,我们将详细探讨C++中的死锁问题,包括其原因、如何检测以及如何避免。

夏天的狂风的专栏 369

C++程序启动报错和启动失败的常见原因分析与排查经验总结

本文对引发C++程序启动报错或启动失败的常见原因及相关排查办法进行了详细地总结,并给出具体的项目问题实战分析实例。相关的总结及实战分析案例均来自于项目实战,有很强的实战参考价值。

dvlinker的技术专栏 4万+

使用lockcop软件检测c++死锁

背景: C++多线程开发中,容易出现死锁导致程序挂起的现象。 工具: lockcop.exe,下载见: 链接:https://pan.baidu.com/s/1UCZaspmHp9I0ekVRbPO5_w 提取码:hv48 测试过程 1.使用VS2017编写一段代码,见下面,调试运行起来,程序名为memeroy.exe, CRITICAL_SECTION cs1; CRITICAL_SECTION cs2; CRITICAL_SECTION csprint; //初始化关键代码段 void.

baidu_16370559的博客 2046

使用 Process Explorer 和 Windbg 排查C++程序线程堵塞问题

本文以项目中遇到的实战案例,详细讲解如何使用 Process Explorer 和 Windbg 排查软件线程堵塞问题。

dvlinker的技术专栏 2040

程序死循环、死锁问题定位

程序死循环、死锁问题定位 在开发过程中,可能由于代码设计问题导致出现了死循环或者死锁的问题,使服务器CPU负载飙高从而导致系统运行缓慢,因此要特别注意防止死循环和死锁的发生。如监控服务器状态时,如果发现CPU负载或利用率飙得很高,这时候就要定位出可能出现的问题,这是在开发中非常重要的能力之一。 主要方法:top 、jstack 定位死循环 模拟一段死循环代码(我这里参考了其他博客的代码来做实验...

qq_41797857的博客 4614

常见的C++软件异常场景分析与总结

根据最近一年多的排查软件异常问题的经历和经验,简单的总结一下软件异常的场景和原因,以供参考。

dvlinker的技术专栏 7997

同花顺PC端逆向解析:Hook注入与加密破解实战指南

在Windows客户端数据采集场景中,当常规HTTP爬虫失效时,内存级逆向分析成为获取实时行情数据的关键路径。其核心涉及进程注入、运行时解密、反调试绕过等底层技术,本质是理解PE加载机制、函数调用约定与内存保护策略的协同过程。同花顺作为典型加固客户端,采用ASPack加壳+自研解密+多线程校验三重防护,迫使开发者转向APC注入、动态密钥提取与XXTEA算法复刻等高阶手段。本文聚焦于DLL注入选型依据、解密函数定位方法及二进制Blob结构化解析,最终实现从内存读取到Pandas DataFrame的端到端数据

weixin_32234493的博客 1199

(Windbg调试四)C++死锁问题定位与分析

C++死锁问题定位与分析一,测试代码二,等待链三,死锁的定位和分析 &amp;amp;amp;nbsp;&amp;amp;amp;nbsp;&amp;amp;amp;nbsp;&amp;amp;amp;nbsp;&amp;amp;amp;nbsp;C++程序异常一般有两种表现形式:程序崩溃和程序无响应。程序崩溃主要是由指针,数组越界等原因引起,这种情况可以直接通过在程序中加入Dump捕捉逻辑,分析dump文件,定位出崩溃的代码。程序无响应主要是由死循环和死锁两个原因

bajianxiaofendui的博客 1万+

PaddleOCR实战:如何在CentOS 8.5上搭建高性能OCR识别环境

本文详细介绍了在CentOS 8.5系统上搭建高性能PaddleOCR识别环境的完整指南。从系统环境准备、PaddlePaddle框架部署到PaddleOCR的定制化安装与性能优化,提供了针对生产环境的解决方案,包括GPU/CPU环境配置、内核参数调优及常见问题排查,帮助用户实现高效OCR识别。

weixin_29223603的博客 349

死锁问题案例分析解决

死锁的问题经常会考察到,面对哪些情况下会程序会发生死锁的问题,与其想着怎么把书上的理论背出来,不如从实践的角度举例说明,如何对死锁的问题进行分析定位,然后找到问题点进行修改。当我们的程序运行时,出现假死的现象,有可能是程序死循环了,有可能是程序等待的I/O、网络事件没发生导致程序阻塞了,也有可能是程序死锁了,下面举例说明在Linux系统下如何分许我们程序的死锁问题。

ljy的博客 884

From Manual to Magic: How nnU-Net is Revolutionizing Biomedical Image Segmentation Without Human Int

本文探讨了nnU-Net如何通过全自动深度学习技术革新生物医学图像分割领域。作为自我配置的智能系统,nnU-Net无需人工干预即可完成从数据预处理到模型训练的全流程,显著提升医学影像分割的效率和精度,尤其在CT和MRI影像分析中表现卓越。

metal的博客 1083

uniapp - 解决控制台提示“同步资源失败,未得到同步资源的授权,请停止运行后重新运行,并注意手机上的授权提示”,uniApp安卓/苹果App真机运行调试显示同步资源失败,无任何授权提示且无法连接

uni-app,报错,安卓Android,苹果ios,安卓app端,苹果App端,uniapp苹果安卓app,提示错误解决,HbuilderX,uniapp同步资源失败,未得到同步资源的授权,请停止运行后重新运行,并注意手机上的授权提示同步失败,安卓基座调试,没有反应,真机没有提示怎么办,如何解决这个问题,苹果ios手机,电脑模拟器运行,adb连接,连接失败,报错出错,uniapp真机运行的时候显示同步资源失败,未得到同步资源的授权,plugins里面没有tools,找不到tools,还是不行,重新打基座

🏆 前端领域优质创作者 1万+

原来jdk自带了这么好玩的工具 > 使用 jstack定位死循环

什么是jstack jstack的主要作用是查看或者导出java线程的堆栈信息(快照);用于堆栈跟踪,当我们使用jstack命令时,它会将指定进程内的所有线程中方法的调用栈打印出来。 线程快照是java虚拟机内每一个线程正在执行的方法堆栈的集合,生成线程快照的主要目的是用于定位线程出现问题的位置;常见的问题有 响应时间长 线程死锁 死循环 当线程停顿的时候通过jstack来查看各个线程的调用堆栈,就可以知道线程的执行过程中在后台做了哪些事,在等待哪些资源造成的卡顿。 使用方法 命令格式 jstack

叶新东老师的博客 3797

多后端系统统一聚合与智能分流:用 Multi Origin Composition 与 Routing 打造一套可扩展的 SAP Gateway 架构

本文针对企业级SAP集成场景,详细介绍了如何利用SAP Gateway的MOC(多源组合)和Routing功能实现多后端系统的智能路由与数据聚合。通过系统别名配置、用户角色绑定和主机名分流等机制,可实现按用户、按域名的精确路由。文章还提供了配置清单、性能优化建议和常见问题解决方案,帮助工程师落地多后端OData服务的最佳实践。

2007 年 ~ 2025 年,深耕 SAP 技术 18 年 186

原来jdk自带了这么好玩的工具 —— 使用 jstack定位死循环

很多人感叹“学习无用”,实际上之所以产生无用论,是因为自己想要的与自己所学的匹配不上,这也就意味着自己学得远远不够。无论是学习还是工作,都应该有主动性,所以如果拥有大厂梦,那么就要自己努力去实现它。最后祝愿各位身体健康,顺利拿到心仪的offer!由于文章的篇幅有限,所以这次的蚂蚁金服和京东面试题答案整理在了PDF文档里《互联网大厂面试真题解析、进阶开发核心学习笔记、全套讲解视频、实战项目源码讲义》点击传送门即可获取![外链图片转存中…(img-kVoaj94O-1713557196480)]

2401_84049040的博客 1796

一文读懂OpenClaw:核心组件与工作原理深度解析

Agent核心:负责理解意图、规划任务、协调执行消息系统:统一的消息格式,实现组件间解耦工具注册表:可扩展的工具系统,支持自定义工具模型适配层:多模型支持,统一API接口安全机制:沙箱隔离、权限确认、操作审计性能优化:并行执行、智能缓存、增量更新理解这些核心组件和工作原理,将帮助你更好地使用OpenClaw,也为后续开发自定义扩展打下坚实基础。在下一篇文章中,我们将详细介绍OpenClaw的界面操作,包括命令行与交互模式的各种技巧。

gaoxiang_120的专栏 833

Python爬取上市公司年报并进行财务比率分析:基于异步爬虫与数据挖掘的实战

在当今数据驱动的投资时代,获取并分析上市公司财务数据对于投资者、分析师和研究人员至关重要。中国证监会指定的上市公司信息披露网站——巨潮资讯网,包含了所有A股上市公司的年报、季报及其他公告信息。本项目将展示如何使用Python最新技术栈爬取巨潮网的年报数据,提取关键财务指标,并进行深入的财务比率分析。本文将采用异步爬虫技术提高数据采集效率,使用现代解析库处理PDF和HTML文档,并结合pandas进行数据分析和可视化。整个过程将遵循合规合法的爬虫伦理,尊重网站robots.txt协议,设置合理的请求间隔。

2201_76125261的博客 666

C++如何排查并发编程死锁问题?

C++如何排查并发编程死锁问题?最近在Apache arrow里面写一个支持并行的算子:nested loop join,然后既然涉及到并行,这里就会遇到大家常说的死锁问题,假设你碰到了死锁问题,如何调试与定位呢?那这便是本篇目标,帮助你快速掌握并发编程:死锁检测与死锁调试问题,非常的干,好了进行正文。1.引入为了更好的讲解死锁,我们用一个程序来引入。std::mutexgMutex; int...

Francis的博客 641

华为OD机试新系统真题-谁没交卷(Java /Py/C++/Go/C/Js)

华为OD机试 新系统真题【谁没交卷】,提供C语言、Java、C++、Python、Go、JavaScript源码实现,并提供完整思路讲解,以及在线OJ模拟做题。华为OD机试真题【谁没交卷】多语言题解。

qq_45776114的博客 421

jstack定位死循环

java

blueheartstone的博客 1230

VB摄像头监控

该VB模块可对摄像头捕获的画面进行录像等,可在创建的窗口进行控制

蓝牙模块HM-10手册

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

使用Windbg精准定位C++多线程死锁问题:从原理到实战

在多线程编程中,死锁是导致程序无响应的经典并发难题,其核心在于多个线程因循环等待资源而永久阻塞。理解互斥锁、临界区等同步原语的工作原理是分析死锁的基础。通过调试工具定位死锁,不仅能解决程序卡死问题,更是深入理解程序并发模型、提升代码健壮性的关键。在Windows平台,Windbg作为强大的底层调试器,结合`!locks`、`!cs`等命令,可以清晰揭示锁的持有与等待关系,帮助开发者绘制出死锁链条。本文以C++多线程场景为例,详细演示如何利用Windbg从线程堆栈分析、锁状态检查到逻辑推理,一步步定位死锁的根

weixin_33859231的博客 423

复分析 阿尔福斯(Ahlfors) 第三版答案 英文

答案分为十章,有部分习题没有答案,全英文复分析阿尔福斯(Ahlfors) 第三版答案

上一篇: Qt WebEngine 实战 - 仿制浏览器(加载进度、放大、缩小、前进、后退、网站图标、历史记录、页面查找)
下一篇: QT 源码分析 - exec 函数
LearnLHC
博客等级 码龄10年 183粉丝 149原创
评论 1
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值