目录

1、问题描述

2、使用.effmach x86命令切换到32位上下文

3、切换到UI线程,发现UI线程死锁了

4、使用!locks命令查看临界区锁的详细信息,遇到了问题

5、使用dt命令查看临界区对象信息,找到发生死锁的多个线程

6、用户态锁与内核态锁

7、最后


C++软件异常排查从入门到精通系列教程(核心精品专栏,订阅量已达8000多个,欢迎订阅,持续更新...)https://blog.csdn.net/chenlycly/article/details/125529931C/C++实战专栏(重点专栏,专栏文章已更新500多篇,订阅量已达6000多个,欢迎订阅,持续更新中...)https://blog.csdn.net/chenlycly/article/details/140824370C++ 软件开发从入门到实战(重点专栏,专栏文章已更新300多篇,欢迎订阅,持续更新中...)https://blog.csdn.net/chenlycly/category_12695902.htmlVC++常用功能开发汇总(专栏文章列表,欢迎订阅,持续更新...)https://blog.csdn.net/chenlycly/article/details/124272585C++软件分析工具从入门到精通案例集锦(专栏文章,持续更新中...)https://blog.csdn.net/chenlycly/article/details/131405795开源组件及数据库技术(专栏文章,持续更新中...)https://blog.csdn.net/chenlycly/category_12458859.html网络编程与网络问题分享(专栏文章,持续更新中...)https://blog.csdn.net/chenlycly/category_2276111.html       最近项目中又遇到了多线程死锁的问题,导出了dump文件,事后用Windbg详细分析了一下。本文详细讲述一下这个多线程死锁问题的完整分析与排查过程,以供借鉴或参考。

1、问题描述

       测试同事在测试新版本软件(新需求迭代,开发了新版本),问题软件终端以SIP协议入会,会议中发起桌面共享,然后测试同事去忙其他事情,20分钟后点击停止发送桌面共享,然后UI界面不能正常显示,且窗口不可点击,估计是UI线程卡死了。

       将Windbg附加到软件进程上,切换到0号UI线程,查看函数调用堆栈,显示线程卡在获取临界区锁的接口上,所以可以确定是UI线程和其他线程发生死锁卡死了。因为调试中的Windbg中输入命令很卡,所以直接到Windows任务管理中导出了软件进程的dump转储文件。因为当前软件不是崩溃闪退,是多线程死锁引发卡死,所以进程还在的,可以从任务管理器中导出dump文件。

       从Windows任务管理器中导出dump文件,是生成dump文件的方式之一,生成dump文件有多种方式。关于dump文件的分类以及生成dump文件的多种方式,可以查看我的文章:

【C++软件调试技术】dump文件类型与dump文件生成方法详解https://blog.csdn.net/chenlycly/article/details/144424512

2、使用.effmach x86命令切换到32位上下文

        从任务管理器中导出的dump文件,用Windbg打开,默认是64位上下文,查看线程函数调用堆栈,显示的堆栈不是正常的堆栈(堆栈中显示的函数不是代码中的函数接口),如下:

而我们的软件是32位的,需要使用.effmach x86命令切换到32位上下文。切换后就可以看到正常的函数调用堆栈,可以看到代码中调用的接口。

       关于使用Windbg分析dump文件的方法与一般步骤,此处不再赘述,可以查看我之前写的文章:

使用Windbg分析dump文件定位软件异常的方法与操作步骤https://blog.csdn.net/chenlycly/article/details/146005441       有时我们需要将Windbg附加到目标进程上进行动态调试,如何使用Windbg进行动态调试,可以查看我之前写的文章:

使用Windbg调试目标进程排查C++软件异常的一般步骤与要点分享https://blog.csdn.net/chenlycly/article/details/145826705

3、切换到UI线程,发现UI线程死锁了

       因为UI界面卡死堵塞了,所以初步怀疑可能是UI线程发生死锁了。当然导致线程卡死,也可能是代码中发生死循环导致函数一直不返回引起的。于是使用~0s命令切换到UI线程,输入kn查看UI线程的函数调用堆栈,如下:

从堆栈中可以看出,UI线程调用了RtlEnterCriticalSection要获取临界区锁,然后最终卡在等待临界区锁的接口NtWaitForAlertByThreadId上了。


       在这里,给大家重点推荐一下我的几个热门畅销专栏,欢迎订阅:(博客主页还有其他专栏,可以去查看)

专栏1:该精品技术专栏的订阅量已达到10000多个,专栏中包含大量项目实战分析案例,有很强的实战参考价值,广受好评!专栏文章持续更新中,已经更新到210篇以上!欢迎订阅!)

C++软件调试与异常排查从入门到精通系列文章汇总https://blog.csdn.net/chenlycly/article/details/125529931

本专栏根据多年C++软件异常排查的项目实践,系统地总结了引发C++软件异常的常见原因以及排查C++软件异常的常用思路与方法详细讲述了C++软件的调试方法与手段详细介绍分析C++软件问题的常用分析工具,以图文并茂的方式给出具体的项目问题实战分析实例(详细讲述分析排查过程,很有实战参考价值),带领大家逐步掌握C++软件调试与异常排查的相关技术,适合基础进阶和想做技术提升的相关C++开发人员!

考察一个开发人员的水平,一是看其编码及设计能力,二是要看其软件调试能力!所以软件调试能力(排查软件异常的能力)很重要,必须重视起来!能解决一般人解决不了的问题,既能提升个人能力及价值,也能体现对团队及公司的贡献!

专栏中的文章都是通过项目实战总结出来的,包含大量项目问题实战分析案例,有很强的实战参考价值!专栏文章还在持续更新中,预计文章篇数能更新到300篇以上!

专栏2:(本专栏涵盖了C++多方面的内容,是当前重点打造的专栏,订阅量已达8000多个,专栏文章已经更新到500多篇,持续更新中...)

C/C++实战进阶(专栏文章,持续更新中...)https://blog.csdn.net/chenlycly/category_11931267.html

以多年的开发实战为基础,总结并讲解一些的C/C++基础与项目实战进阶内容,以图文并茂的方式对相关知识点进行详细地展开与阐述!专栏涉及了C/C++领域多个方面的内容,包括C++基础及编程要点(模版泛型编程、STL容器及算法函数的使用等)、数据结构与算法C++11及以上新特性(开源代码中可能会用到很多新特性(比如WebRTC开源库),日常编码中也会用到部分新特性,面试时也会频繁地涉及到,学习新特性很有必要)、常用C++开源库的介绍与使用(比如SQLite、libcurl、libwebsockets、libevent、jsoncpp/RapidJson、Redis、RabbitMQ、MongoDB、MQTT、ZooKeeper、OpenCV、FFmpeg、SDL、GStreamer、Live555、ReactOS等)、代码分享(调用系统API、使用开源库)、常用编程技术(动态库、多线程、多进程、数据库及网络编程等)、软件UI编程(Win32/duilib/QT/MFC)、C++软件调试技术(引发C++软件异常的常见原因分析与总结、排查C++软件异常的手段与方法、分析C++软件异常的基础知识、使用常用软件分析工具分析C++软件问题、多个项目实战问题分析案例分享等)、设计模式(单例模式、工厂模式、观察者模式、状态模式等)、网络基础知识与网络问题分析进阶内容(实战问题分析实例分享)等。本专栏的内容都是建立在项目实践的基础上,来源于项目实战,服务于项目实战,很有实战参考价值!

专栏3:  

C++常用软件分析工具从入门到精通案例集锦汇总(专栏文章,持续更新中...)https://blog.csdn.net/chenlycly/article/details/131405795

常用的C++软件辅助分析工具有SPY++、PE工具、Dependency Walker、GDIView、Process Explorer、Process Monitor、API Monitor、Clumsy、Windbg、IDA Pro等,本专栏详细介绍如何使用这些工具去巧妙地分析和解决日常工作中遇到的问题,很有实战参考价值!

专栏4:   

VC++常用功能开发汇总(专栏文章,持续更新中...)https://blog.csdn.net/chenlycly/article/details/124272585

将10多年C++开发实践中常用的功能,以高质量的代码展现出来。这些常用的高质量规范代码,可以直接拿到项目中使用,能有效地解决软件开发过程中遇到的问题。

专栏5: 

C++ 软件开发从入门到精通(专栏文章,持续更新中...)https://blog.csdn.net/chenlycly/category_12695902.html

根据多年C++软件开发实践,详细地总结了C/C++软件开发相关技术实现细节,分享了大量的实战案例,很有实战参考价值。


4、使用!locks命令查看临界区锁的详细信息,遇到了问题

       输入kv命令,将堆栈中传入的参数值打印出来,如下所示:

对于临界区对象锁,调用的是RtlEnterCriticalSection,传入的是临界区结构体CRITICAL_SECTION对象地址,所以UI线程等待的临界区对象地址就是堆栈中的参数值087d89f0。

       于是输入命令!locks,查看当前临界区对象信息,看看087d89f0临界区锁被哪个线程占用了。输入后提示:

提示没法解析ntdll.dll库中的RtlCriticalSectionList接口,应该是没有设置系统pdb下载地址的问题。于是将微软系统库pdb在线下载地址srv*f:\mss0616*http://msdl.microsoft.com/download/symbols设置到windbg中,重新输入!locks,结果还是提示有问题:

没法读取dump文件中的内存,当前dump文件中的内存数据不全?奇怪了,当前的dump文件是从资源管理器中导出的,应该是全dump文件,咋还没法读取内存呢?难道从正在调试的Windbg中导出的dump文件才是包含所有内存的dump文件?让测试同事那边把Windbg附加到程序进程中重新复现一下,然后从正在调试的Windbg中导出dump文件再分析一下?

       关于pdb符号文件以及如何使用pdb符号文件,可以查看我之前写的文章:

【C++软件调试技术】什么是pdb文件?如何使用pdb文件?哪些工具需要使用pdb文件?https://blog.csdn.net/chenlycly/article/details/140742876

5、使用dt命令查看临界区对象信息,找到发生死锁的多个线程

       既然!locks命令没法查看到当前软件进程中的临界区对象信息,我们可以尝试使用dt命令看一下。我们上面已经知道UI线程在等待临界区锁087d89f0(临界区结构体CRITICAL_SECTION对象地址),可以使用“dt RTL_CRITICAL_SECTION 087d89f0”命令,把地址087d89f0当成RTL_CRITICAL_SECTION结构体对象的首地址,从而获取到该地址对应的结构体对象的字段值,如下所示:

其中的OwningThread字段就是当前临界区锁被哪个线程占用了(还没释放)。因为占用该临界区锁的线程没有释放锁,导致UI线程一直获取不到锁,一直在等待,产生死锁。

       OwningThread字段值 0x00003bc8就是线程id,于是使用~*命令,将当前进程中的所有信息打印出来:

找到线程id为0x00003bc8的线程对应的线程号,对应38号线程。

       于是使用~38s命令,切换到38号线程,使用kn命令将该线程的函数调用堆栈打印出来,看看为什么占用了临界区锁087d89f0没有释放。38号线程的函数调用堆栈如下:

38号线程也卡住了,卡在NtWaitForSingleObject接口上,沿着调用堆栈向上看,是在等待mutex互斥量锁。38号线占用了临界区锁087d89f0,因为38号线程在等待另一个mutex互斥量锁,所以没有释放临界区锁087d89f0,所以导致UI线程一直拿不到临界区锁087d89f0产生了堵塞卡死。至于38号线一直在等待mutex互斥量锁,肯定这个互斥量锁被第三个线程占用了,导致38号线程卡死了。

6、用户态锁与内核态锁

       本案例中涉及到的锁有临界区和mutex互斥锁,前者是用户态锁,后者是内核态锁。

       用于多线程之间同步的常用锁有临界区、事件、信号量和互斥量等,其中临界区是Windows系统独有的,是用户态锁,事件、信号量和互斥量则是内核态锁。用户态锁在访问时不需要进行用户态与内核态的切换,效率比较高。对于内核态锁,访问时要进行用户态与内核态之间的切换,相对于用户态锁,访问效率要低一些。我们的业务代码运行在用户态,当调用系统API访问内核态锁时,API函数底层需要从用户态切换到内核态,访问完后,再从内核态返回到用户态,这就是用户态与内核态之间的切换。

       出于访问锁的效率问题,一般在Windows平台会优先使用临界区锁。在很多支持跨平台的开源代码中,封装的锁在Windows平台上都被定义成临界区锁。

7、最后

        所以本案例中应该是3个线程之间发生了死锁。因为当前发生死锁的多个线程属于底层的音视频编解码模块,所以这个问题的后续排查只能交给该模块的开发团队了,我这边的排查工作就基本完成了。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/web/92758.shtml
繁体地址,请注明出处:http://hk.pswp.cn/web/92758.shtml
英文地址,请注明出处:http://en.pswp.cn/web/92758.shtml

如若内容造成侵权/违法违规/事实不符,请联系英文站点网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

防火墙组网方式总结

一、部署模式:灵活适配多样网络环境下一代防火墙(NGAF)具备极强的网络适应能力,支持五种核心部署模式,可根据不同网络需求灵活选择。路由模式:防火墙相当于路由器,位于内外网之间负责路由寻址&a…

AI大模型:(二)5.1 文生视频(Text-to-Video)模型发展史

目录 1.介绍 2.发展历史 2.1.早期探索阶段(2015-2019) 2.1.1.技术萌芽期 2.1.2.RNN/LSTM时代 2.2.技术突破期(2020-2021) 2.2.1 Transformer引入视频生成 2.2.2 扩散模型的兴起 2.3.商业化突破期(2022-2023) 2.3.1 产品化里程碑 2.3.2 竞争格局形成 2.4.革命…

14mm寻北仪能否塞进液压支架生死缝隙?

在煤矿井下世界的方寸之间,液压支架的每个关键节点都承载着千钧重压。顶梁铰接点、立柱顶端、掩护梁角落,恰恰是空间最为局促的“禁区”。ER-MNS-10A MEMS寻北仪应运而生!它采用了先进的MEMS陀螺技术,以14mm至薄高度、40g极致轻盈…

python之浅拷贝深拷贝

文章目录潜拷贝(shallow copy)深拷贝(deep copy)总结一下python的浅拷贝和深拷贝.潜拷贝(shallow copy) python中潜拷贝指的是:构造一个新的复合对象,然后将原对象中的对象引用插入其中 平常开发过程中潜拷贝是比深拷贝更常见的场景. 比如编程中使用到的一些基本的…

普通大学本科生如何入门强化学习?

问题:你平时是如何紧跟大型语言模型和智能体技术前沿的?有哪些具体的学习和跟踪方式?回答:我会通过“输入-内化-实践”结合的方式跟踪前沿。首先,学术动态方面,每天花10分钟浏览arXiv的http://cs.CL和http://cs.AI板块&#xff0c…

新手向:Python实现数据可视化图表生成

Python数据可视化入门:从零开始生成图表数据可视化是数据分析过程中不可或缺的关键环节,它通过将抽象的数字信息转化为直观的图形展示,帮助分析师和决策者更快速、更准确地发现数据中隐藏的模式、规律和发展趋势。在当今大数据时代&#xff0…

VBA即用型代码手册:计算选择的单词数Count Words in Selection

我给VBA下的定义:VBA是个人小型自动化处理的有效工具。可以大大提高自己的劳动效率,而且可以提高数据的准确性。我这里专注VBA,将我多年的经验汇集在VBA系列九套教程中。作为我的学员要利用我的积木编程思想,积木编程最重要的是积木如何搭建及…

DNS(域名系统)

分层结构根域名(ipv4,13台),二级域名,三级域名……相关记录A将域名解析为ipv4地址AAAA将域名解析为ipv6地址MX指名该区域为邮件服务区PTR反向查询将主机名解析为域名NS记录服务器的名字CNAME别名查询方式递归查询迭代查…

【大模型】强化学习算法总结

角色和术语定义 State:状态Action:动作Policy/actor model:策略模型,用于决策行动的主要模型Critic/value model:价值模型,用于评判某个行动的价值大小Reward model:奖励模型,用于给…

基于梅特卡夫定律的开源链动2+1模式AI智能名片S2B2C商城小程序价值重构研究

摘要:梅特卡夫定律揭示了网络价值与用户数量的平方关系,在互联网经济中,连接的深度与形式正因人的参与发生质变。本文以开源链动21模式、AI智能名片与S2B2C商城小程序的协同应用为研究对象,通过实证分析其在社群团购、下沉市场等场…

Ubuntu22.04安装CH340驱动及串口

一、CH340驱动安装 1.1 查看USB设备能否被识别 CtrlAltT打开终端: lsusb 插入设备前: 插入设备后: 输出中包含ID 1a86:7523 QinHeng Electronics CH340 serial converter的信息,这表明CH340设备已经被系统识别。 1.2 查看USB转串…

CPU缓存(CPU Cache)和TLB(Translation Lookaside Buffer)缓存现代计算机体系结构中用于提高性能的关键技术

CPU缓存(CPU Cache)和TLB(Translation Lookaside Buffer)缓存是现代计算机体系结构中用于提高性能的关键技术。它们通过减少CPU访问数据和指令的延迟来提高系统的整体效率。以下是对这两者的详细解释: 1. CPU 缓存 CPU…

唐扬·高并发系统设计40问

课程下载:https://download.csdn.net/download/m0_66047725/91644703 00开篇词 _ 为什么你要学习高并发系统设计?.pdf 00开篇词丨为什么你要学习高并发系统设计?.mp3 01 _ 高并发系统:它的通用设计方法是什么?.pdf …

基于Spring Data Elasticsearch的分布式全文检索与集群性能优化实践指南

基于Spring Data Elasticsearch的分布式全文检索与集群性能优化实践指南 技术背景与应用场景 随着大数据时代的到来,海量信息的存储与检索成为各类应用的核心需求。Elasticsearch 作为一款分布式搜索引擎,凭借其高可扩展、高可用和实时检索的优势&#x…

Linux系统编程——基础IO

一些前置知识:文件 属性 内容文件 分为 打开的文件、未打开的文件打开的文件:由进程打开,本质是 进程与文件 的关系;维护的文件对象先加载文件属性,文件内容一般按需加载未打开的文件:在永久性存储介质 —…

力扣164:最大间距

力扣164:最大间距题目思路代码题目 给定一个无序的数组 nums,返回 数组在排序之后,相邻元素之间最大的差值 。如果数组元素个数小于 2,则返回 0 。 您必须编写一个在「线性时间」内运行并使用「线性额外空间」的算法。 思路 这道题的思路…

Redis类型之Hash

1.hash常用操作 这里还是要强调,redis的类型指的是value的类型。故而这里的hash是把key这一层组织完成以后,到了value这一层,value的其中一种类型还可以是hash。1.1 HSET 和 HGETHSET:设置hash类型的keyHSET key field value [fie…

Apache Pulsar性能与可用性优化实践指南

Apache Pulsar性能与可用性优化实践指南 一、技术背景与应用场景 随着微服务、实时计算和大数据平台的普及,消息系统承担了海量数据的传输与解耦任务。Apache Pulsar作为新一代分布式消息与流处理系统,拥有多租户、持久化存储和灵活一致性的特点&#xf…

工单分类微调训练运维管理工具原型

简述需求进展之前,我尝试用Longformer模型来训练工单分类系统,但问题很快就暴露出来:Longformer训练时间长得让人抓狂,每次训练只能针对一个租户的数据,无法快速适配多个租户的需求。切换一个使用相同标签的租户还能够…

@CacheConfig​​当前类中所有缓存方法详解

CacheConfig​​当前类中所有缓存方法详解在 Spring Cache 抽象中,CacheConfig 是一个​​类级别注解​​,用于为​​当前类中的所有缓存方法(如 Cacheable、CachePut、CacheEvict)提供默认配置​​。其核心作用是​​避免在每个方…