关于使用WinDebug查看线程死锁问题

最近项目接近尾声,不过项目到了测试的时候大问题来了,偶尔界面直接卡死以至于后续无法测试,初步怀疑是哪里死锁了,由于自己对WinDebug不是很熟悉,只知道WinDebug有查找内存泄露问题、线程死锁等相关功能,于是吩咐下面的人用winDebug去查找问题,索性网络资源比较多,通过一番调研找到了WInDebug死锁查找的解决方法,不过作为项目开发经理,遇到死锁的事应该能够在其他同时不能解决的时候也能提供相应的帮助是理所当然的,于是带着这种心态去学习了WinDebug查找死锁的方法,总结如下:

死锁,成立的条件就是:

(1)起码有两把锁以上,假如仅有两把锁,且为锁A和锁B;

(2)线程1已经拿了一把锁A然后还想去拿锁B;线程2已经拿了一把锁B然后还想去拿锁A;

(3)没有拿到另一把锁不强行释放自己获取的锁;

于是,死锁来了~

实现所有的实例:

(1)初始化两把锁A和B,启动两个线程(可以一个主线程和一个子线程);

(2)第一个线程已经拿了锁A,第二个线程已经拿了锁B,第一线程尝试去拿锁B,第二线程尝试去拿锁A;

基于以上思想,我写了一个Demon,出现了死锁情况,然后使用WinDebug查找死锁情况,方法介绍如下:

(1)启用应用程序的用户堆栈功能-我使用winDebug开始没有启用导致WinDebug绑定进程失败;

方法使用WinDebug目录下的gflags.exe:打开命令行,进入WinDebug目录运行:gflag.exe /i  调试exe的全路径 +ust

然后回车,ust 就是 user stack用户堆栈;

(2)打开WinDebug然后选择File-->Attach to Process 附加到需要调试的进程exe;

如果需要查看所有线程堆栈那么在命令窗口输入:~*kv

输出如下所有线程堆栈:

此时能打开所有线程的堆栈,如果需要看某一线程的堆栈,则输入*1kv也就是打印线程1的堆栈;从所有线程的堆栈中我们可以看到各个线程的堆栈信息,如果此时有堆栈锁,一般都在栈顶会有API调用:ntdll!RtlpWaitOnCriticalSection,也就是找到所有的该API调用我们就可以找到对应的死锁线程信息;

0  Id: 11264.10f20 Suspend: 1 Teb: 7efdd000
Unfrozen

ChildEBP RetAddr  Args to Child

003eecd8 77709e2e 00000124 00000000 00000000 ntdll!ZwWaitForSingleObject+0x15 (FPO: [3,0,0])

003eed3c 77709d12 00000000 00000000 00000001 ntdll!RtlpWaitOnCriticalSection+0x13e (FPO: [Non-Fpo])

003eed64 0113e289 0161cd80 c3c8e76a 00000001 ntdll!RtlEnterCriticalSection+0x150 (FPO: [Non-Fpo])

003eee7c 011548ff 003ef808 003eeeb4 757d62fa LockDemon!CLockDemonDlg::OnInitDialog+0x179 (FPO: [Non-Fpo]) (CONV: thiscall) [e:\work\c++\test\lockdemon\lockdemon\lockdemondlg.cpp @ 122]

003eee88 757d62fa 002d1984 00000110 001d1b26 LockDemon!AfxDlgProc+0x3f (CONV: stdcall) [f:\dd\vctools\vc7libs\ship\atlmfc\src\mfc\dlgcore.cpp @ 28]

003eeeb4 757ff9df 01119035 002d1984 00000110 USER32!InternalCallWinProc+0x23

003eef30 757ff784 00000000 01119035 002d1984 USER32!UserCallDlgProcCheckWow+0xd7 (FPO: [Non-Fpo])

003eef80 757ff889 0409a140 00000000 00000110 USER32!DefDlgProcWorker+0xb7 (FPO: [Non-Fpo])

003eefa0 757d62fa 002d1984 00000110 001d1b26 USER32!DefDlgProcW+0x29 (FPO: [Non-Fpo])

003eefcc 757d6d3a 77734308 002d1984 00000110 USER32!InternalCallWinProc+0x23

003ef044 757e0d27 00000000 77734308 002d1984 USER32!UserCallWinProcCheckWow+0x109 (FPO: [Non-Fpo])

003ef07c 757e0d4d 77734308 002d1984 00000110 USER32!CallWindowProcAorW+0xab (FPO: [Non-Fpo])

003ef09c 0115e4d4 77734308 002d1984 00000110 USER32!CallWindowProcW+0x1b (FPO: [Non-Fpo])

003ef0c0 0115c5fd 00000110 001d1b26 00000000 LockDemon!CWnd::DefWindowProcW+0x34 (CONV: thiscall) [f:\dd\vctools\vc7libs\ship\atlmfc\src\mfc\wincore.cpp @ 1043]

003ef0dc 01156235 003ef808 003ef0f8 012282d3 LockDemon!CWnd::Default+0x3d (CONV: thiscall) [f:\dd\vctools\vc7libs\ship\atlmfc\src\mfc\wincore.cpp @ 274]

003ef100 011603e5 001d1b26 00000000 c3c8fb46 LockDemon!CDialog::HandleInitDialog+0xd5 (CONV: thiscall) [f:\dd\vctools\vc7libs\ship\atlmfc\src\mfc\dlgcore.cpp @ 673]

003ef250 0115fb62 00000110 001d1b26 00000000 LockDemon!CWnd::OnWndMsg+0x835 (CONV: thiscall) [f:\dd\vctools\vc7libs\ship\atlmfc\src\mfc\wincore.cpp @ 2018]

003ef270 0115c400 00000110 001d1b26 00000000 LockDemon!CWnd::WindowProc+0x32 (CONV: thiscall) [f:\dd\vctools\vc7libs\ship\atlmfc\src\mfc\wincore.cpp @ 1755]

003ef2ec 0115cb16 003ef808 002d1984 00000110 LockDemon!AfxCallWndProc+0xf0 (CONV: stdcall) [f:\dd\vctools\vc7libs\ship\atlmfc\src\mfc\wincore.cpp @ 240]

003ef30c 757d62fa 002d1984 00000110 001d1b26 LockDemon!AfxWndProc+0xa6 (CONV: stdcall) [f:\dd\vctools\vc7libs\ship\atlmfc\src\mfc\wincore.cpp @ 403]

003ef338 757d6d3a 01127310 002d1984 00000110 USER32!InternalCallWinProc+0x23

003ef3b0 757d6de8 00000000 01127310 002d1984 USER32!UserCallWinProcCheckWow+0x109 (FPO: [Non-Fpo])

003ef40c 757d6e44 0409a140 00000000 00000110 USER32!DispatchClientMessage+0xe0 (FPO: [Non-Fpo])

003ef448 776e010a 003ef460 00000000 003ef694 USER32!__fnDWORD+0x2b (FPO: [Non-Fpo])

003ef45c 0409a140 00000000 00000110 001d1b26 ntdll!KiUserCallbackDispatcher+0x2e (FPO: [0,0,0])

WARNING: Frame IP not in any known module. Following frames may be wrong.

003ef4c0 7580206f 0409a140 00000000 01127310 0x409a140

003ef594 758010d3 00f00000 00000006 000000a4 USER32!InternalCreateDialog+0xb9f (FPO: [Non-Fpo])

003ef5b8 757ec659 00f00000 0163fdc8 00000000 USER32!CreateDialogIndirectParamAorW+0x33 (FPO: [Non-Fpo])

003ef5d8 01155513 00f00000 0163fdc8 00000000 USER32!CreateDialogIndirectParamW+0x1b (FPO: [Non-Fpo])

003ef6a0 01155e39 0163fdc8 00000000 00f00000 LockDemon!CWnd::CreateDlgIndirect+0x263 (CONV: thiscall) [f:\dd\vctools\vc7libs\ship\atlmfc\src\mfc\dlgcore.cpp @ 312]

003ef714 0113da0d c3c8f1a6 00000000 00000000 LockDemon!CDialog::DoModal+0x199 (CONV: thiscall) [f:\dd\vctools\vc7libs\ship\atlmfc\src\mfc\dlgcore.cpp @ 576]

003ef8b0 0153da94 757d9ee1 003ef8c0 00280026 LockDemon!CLockDemonApp::InitInstance+0xad (CONV: thiscall) [e:\work\c++\test\lockdemon\lockdemon\lockdemon.cpp @ 64]

003ef8d4 0153d98a 00f00000 00000000 006710b4 LockDemon!AfxWinMain+0x84 (CONV: stdcall) [f:\dd\vctools\vc7libs\ship\atlmfc\src\mfc\winmain.cpp @ 37]

003ef8ec 014c1015 00f00000 00000000 006710b4 LockDemon!wWinMain+0x1a (CONV: stdcall) [f:\dd\vctools\vc7libs\ship\atlmfc\src\mfc\appmodul.cpp @ 34]

003ef990 014c0e9f 003ef9a4 76e0336a 7efde000 LockDemon!__tmainCRTStartup+0x165 (CONV: cdecl) [f:\dd\vctools\crt_bld\self_x86\crt\src\crt0.c @ 263]

003ef998 76e0336a 7efde000 003ef9e4 777092b2 LockDemon!wWinMainCRTStartup+0xf (CONV: cdecl) [f:\dd\vctools\crt_bld\self_x86\crt\src\crt0.c @ 182]

003ef9a4 777092b2 7efde000 61654582 00000000 kernel32!BaseThreadInitThunk+0xe (FPO: [Non-Fpo])

003ef9e4 77709285 0111a958 7efde000 00000000 ntdll!__RtlUserThreadStart+0x70 (FPO: [Non-Fpo])

003ef9fc 00000000 0111a958 7efde000 00000000 ntdll!_RtlUserThreadStart+0x1b (FPO: [Non-Fpo])

1  Id: 11264.11284
Suspend: 1 Teb: 7efda000 Unfrozen

ChildEBP RetAddr  Args to Child

0631fe7c 759714ab 00000104 00000000 00000000 ntdll!ZwWaitForSingleObject+0x15 (FPO: [3,0,0])

0631fee8 76e01194 00000104 ffffffff 00000000 KERNELBASE!WaitForSingleObjectEx+0x98 (FPO: [Non-Fpo])

0631ff00 76e01148 00000104 ffffffff 00000000 kernel32!WaitForSingleObjectExImplementation+0x75 (FPO: [Non-Fpo])

0631ff14 7235107b 00000104 ffffffff 76e010ff kernel32!WaitForSingleObject+0x12 (FPO: [Non-Fpo])

WARNING: Stack unwind information not available. Following frames may be wrong.

0631ff58 7235290a 72377db8 76e0336a 72377db8 CKSee+0x107b

0631ff6c 777092b2 72377db8 676a43ca 00000000 CKSee!Kinkoo_GetInterface+0x13aa

0631ffac 77709285 72352900 72377db8 00000000 ntdll!__RtlUserThreadStart+0x70 (FPO: [Non-Fpo])

0631ffc4 00000000 72352900 72377db8 00000000 ntdll!_RtlUserThreadStart+0x1b (FPO: [Non-Fpo])

2  Id: 11264.9238 Suspend: 1 Teb: 7efd7000 Unfrozen

ChildEBP RetAddr  Args to Child

064efbf4 77709e2e 00000120 00000000 00000000 ntdll!ZwWaitForSingleObject+0x15 (FPO: [3,0,0])

064efc58 77709d12 00000000 00000000 005819a0 ntdll!RtlpWaitOnCriticalSection+0x13e (FPO: [Non-Fpo])

064efc80 01140f78 0161cd68 00000000 00000000 ntdll!RtlEnterCriticalSection+0x150 (FPO: [Non-Fpo])

064efd58 014c22e3 003ef808 c5b8f482 00000000 LockDemon!MyFunc+0x48 (FPO: [Non-Fpo]) (CONV: stdcall) [e:\work\c++\test\lockdemon\lockdemon\lockdemondlg.cpp @ 79]

064efd94 014c2254 00000000 064efdac 76e0336a LockDemon!_callthreadstartex+0x53 (CONV: cdecl) [f:\dd\vctools\crt_bld\self_x86\crt\src\threadex.c @ 348]

064efda0 76e0336a 005819a0 064efdec 777092b2 LockDemon!_threadstartex+0xa4 (CONV: stdcall) [f:\dd\vctools\crt_bld\self_x86\crt\src\threadex.c @ 331]

064efdac 777092b2 005819a0 6715418a 00000000 kernel32!BaseThreadInitThunk+0xe (FPO: [Non-Fpo])

064efdec 77709285 014c21b0 005819a0 00000000 ntdll!__RtlUserThreadStart+0x70 (FPO: [Non-Fpo])

064efe04 00000000 014c21b0 005819a0 00000000 ntdll!_RtlUserThreadStart+0x1b (FPO: [Non-Fpo])

#  3  Id: 11264.1175c Suspend: 1 Teb: 7ef9f000 Unfrozen

ChildEBP RetAddr  Args to Child

0580fcf8 7776fb96 64db414e 00000000 00000000 ntdll!DbgBreakPoint (FPO: [0,0,0])

0580fd28 76e0336a 00000000 0580fd74 777092b2 ntdll!DbgUiRemoteBreakin+0x3c (FPO: [Non-Fpo])

0580fd34 777092b2 00000000 64db4112 00000000 kernel32!BaseThreadInitThunk+0xe (FPO: [Non-Fpo])

0580fd74 77709285 7776fb5a 00000000 00000000 ntdll!__RtlUserThreadStart+0x70 (FPO: [Non-Fpo])

0580fd8c 00000000 7776fb5a 00000000 00000000 ntdll!_RtlUserThreadStart+0x1b (FPO: [Non-Fpo])

由此可以看出总共有0-3号4个线程,绿色的表示线程线程索引号,蓝色的表示线程的地址(11264.1175c中11264位线程ID,1175c为线程地址),当然所有线程打印出来一个一个找锁不容易观察到死锁,为了能直接打印进程中线程之间的死锁,直接使用如下命令

首先,查看进程中所有的锁,输入命令 :  !locks,如下:

0:003> !locks

此时打印出进程中所有的锁信息:

CritSec LockDemon!g_LockA+0 at 0161cd80

WaiterWoken        No

LockCount          1

RecursionCount     1

OwningThread       9238

EntryCount         0

ContentionCount    1

*** Locked

CritSec LockDemon!g_LockB+0 at 0161cd68

WaiterWoken        No

LockCount          1

RecursionCount     1

OwningThread       10f20

EntryCount         0

ContentionCount    1

*** Locked

第一把锁地址为0161cd80,LockCount表示占有该锁的数目,RecursionCount  表示拥有者线程进入该锁的次数(进入拿到锁后还可以进入多次),OwningThread 拥有者线程为9238,也就是说0161cd80锁被地址为9238线程占用,也就是线程索引号为2 ,线程ID为11264线程地址为9238 的线程已经拿了锁0161cd80,却在等待锁 0161cd68

第二把锁地址为0161cd68,LockCount表示占有该锁的数目,RecursionCount  表示拥有者线程进入该锁的次数(进入拿到锁后还可以进入多次),OwningThread 拥有者线程为10f20,也就是说0161cd68锁被地址为10f20线程占用,也就是线程索引号为0 ,线程ID为11264线程地址为10f20的线程已经拿了锁0161cd68,却在等待锁 0161cd80

这样死锁就这么被确定下来,线程0和线程2互锁!

堆栈列信息解释如下:

2  Id: 11264.9238 Suspend: 1 Teb: 7efd7000 Unfrozen

ChildEBP RetAddr  Args to Child

064efbf4 77709e2e 00000120 00000000 00000000 ntdll!ZwWaitForSingleObject+0x15 (FPO: [3,0,0])

064efc58 77709d12 00000000 00000000 005819a0 ntdll!RtlpWaitOnCriticalSection+0x13e (FPO: [Non-Fpo])

064efc80 01140f78 0161cd68 00000000 00000000 ntdll!RtlEnterCriticalSection+0x150 (FPO: [Non-Fpo])

064efd58 014c22e3 003ef808 c5b8f482 00000000 LockDemon!MyFunc+0x48 (FPO: [Non-Fpo]) (CONV: stdcall) [e:\work\c++\test\lockdemon\lockdemon\lockdemondlg.cpp @ 79]

064efd94 014c2254 00000000 064efdac 76e0336a LockDemon!_callthreadstartex+0x53 (CONV: cdecl) [f:\dd\vctools\crt_bld\self_x86\crt\src\threadex.c @ 348]

064efda0 76e0336a 005819a0 064efdec 777092b2 LockDemon!_threadstartex+0xa4 (CONV: stdcall) [f:\dd\vctools\crt_bld\self_x86\crt\src\threadex.c @ 331]

064efdac 777092b2 005819a0 6715418a 00000000 kernel32!BaseThreadInitThunk+0xe (FPO: [Non-Fpo])

064efdec 77709285 014c21b0 005819a0 00000000 ntdll!__RtlUserThreadStart+0x70 (FPO: [Non-Fpo])

064efe04 00000000 014c21b0 005819a0 00000000 ntdll!_RtlUserThreadStart+0x1b (FPO: [Non-Fpo])

第三列也就是后面API的第一个参数,对于API 即RtlEnterCriticalSection的第一个参数也就是第三列就是锁的地址,也就是线程id为2(线程地址为0x9238)的线程在等锁0x0161cd68

版权声明:本文为博主原创文章,未经博主允许不得转载。

时间: 2024-07-30 17:08:03

关于使用WinDebug查看线程死锁问题的相关文章

线程系列08,实现线程锁的各种方式,使用lock,Montor,Mutex,Semaphore以及线程死锁

当涉及到多线程共享数据,需要数据同步的时候,就可以考虑使用线程锁了.本篇体验线程锁的各种用法以及线程死锁.主要包括: ※ 使用lock处理数据同步※ 使用Monitor.Enter和Monitor.Exit处理数据同步※ 使用Mutex处理进程间数据同步※ 使用Semaphore处理数据同步※ 线程死锁 □ 使用lock处理数据同步 假设有一个类,主要用来计算该类2个字段的商,在计算商的方法之内让被除数自减,即被除数有可能为零.使用lock语句块保证每次只有一个线程进入该方法. class Th

jstack(查看线程)、jmap(查看内存)和jstat(性能分析)命令

公司内部同事分享的一篇文章 周末看到一个用jstack查看死锁的例子.昨天晚上总结了一下jstack(查看线程).jmap(查看内存)和jstat(性能分析)命令.供大家参考 1.Jstack 1.1   jstack能得到运行java程序的java stack和native stack的信息.可以轻松得知当前线程的运行情况.如下图所示 注:这个和thread dump是同样的结果.但是thread dump是用kill -3 pid命令,还是服务器上面少用kill为妙 1.2   命名行格式

Atitit.线程 死锁 跑飞 的检测与自动解除 与手动解除死锁 java c# .net php javascript.

Atitit.线程 死锁 跑飞 的检测与自动解除 与手动解除死锁 java c# .net php javascript. 1. 现象::主程序卡住无反应,多行任务不往下执行 1 2. 原因::使用jv jprofile查看线程,原来俩个线程死锁了.. 1 3. Java的缺点,默认不能自动解除死锁 1 4. 自动检测与解除死锁::使用看门狗watchdog 2 4.1. 死锁检测算法(太麻烦,不推荐) 2 4.2. 硬件看门狗 2 4.3. 软件看门狗的实现--TIMER 2 4.4. LIN

线程死锁的思考

线程死锁的思考 前言 前些天在公司这边写了个豌豆荚的爬虫,用到了分区思想和自己实现的线程池,我自己觉得从这个过程中学到了很多东西,包括如何去设计接口和方便扩展以及代码的规范化.之前用小数据量测试了发现没什么问题,后来拿了W级以上的问题,发现插入的数码条目的量级和输入量级有很大差异,就算算上失效的URL也不应出现这样的情况,于是开始排查.反反复复看各个模块的代码,对应日志信息查看,最后发现时死锁问题导致的. 什么是死锁? 死锁(英语:Deadlock),又译为死锁,计算机科学名词.当两个以上的运算

性能测试三十七:线程死锁和阻塞

一.线程死锁 线程死锁就是有两个以上的线程,一个线程锁住了资源A,又想去锁定资源B,另外一个线程锁定了资源B,又想去锁定资源A,两个线程都想去得到对方的资源,而又不愿释放自己的资源从而造成一种互相等待,无法执行的情况 接口:http://localhost:8080/PerfTeach/DeadServlet 因为要出现线程死锁至少要2个用户,所以用3个并发,永远跑 TPS: 响应时间 使用jstat -gcutil查看,JVM正常 使用dstat -tcdlmnsygr查看,cpu没什么压力

线程死锁

所谓的线程死锁,是指在多线程运行的过程中,线程1拥有锁a,而需要锁b来继续执行, 而此时,线程2拥有锁b而需要锁a来继续执行,那么此时会形成死锁,两个线程会同时等待. 在编程的过程中应尽量的避免线程死锁. 有时在面试中会要求写出一个死锁的程序演示,如下: 1 //写一个死锁程序 2 public class DeadLock { 3 //主程序执行 4 public static void main(String[] args) { 5 Thread thread1 = new Thread(n

在Linux下线程死锁的四个条件

一.死锁的原因和必要条件 1.死锁的概念 一般情况下,如果同一个线程先后两次调用lock,在第一次调用时,由于锁已经被占,该线程会挂起等待别的线程释放锁,然而锁正是被自己占着的,该线程又被挂起,没有机会释放锁,因此,就永远处于挂起等待状态了,这叫做死锁(Deadlock).另种典型的死锁情形是这样:线程A获 得了锁1,线程B获得了锁2,这时线程A调用lock试图获得锁2,结果是需要挂起等待线程B释放锁2,而这时线程B也调用lock试图获得锁1,结果是需要挂起等待线程A释放锁1,于是线程A和B都永

Java笔记六.线程同步、线程死锁

线程同步.线程死锁 在上一篇文章中,有一个模拟售卖火车票系统,在卖车票的程序代码中,极有可能碰到一种意外,就是同一张票号被打印两次多次,也可能出现打印出0甚至负数的票号.具体表现为:假设tickets的值为1的时候,线程1刚执行完if(tickets>0)这行代码,正准备执行下面的代码,就在这时,操作系统将CPU切换到了线程2上执行,此时tickets的值仍为1,线程2执行完上面两行代码,tickets的值变为0后,CPU又切回到了线程1上执行,线程1不会再执行if(tickets>0)这行代

JAVA笔记14__多线程共享数据(同步)/ 线程死锁 /

/** * 多线程共享数据 * 线程同步:多个线程在同一个时间段只能有一个线程执行其指定代码,其他线程要等待此线程完成之后才可以继续执行. * 多线程共享数据的安全问题,使用同步解决. * 线程同步两种方法: * 1.同步代码块 * synchronized(要同步的对象){ 要同步的操作 } * 2.同步方法 * public synchronized void method(){ 要同步的操作 } */ public class Main { public static void main(