windbg wdk下载
下载地址,安装的时候选择Debugging Tools For Windows
即可
windbg 使用
通过File
/Attach to a process
,快捷键F6
附加到已经阻塞的程序中
查看所有线程的堆栈信息
- k* 命令显示给定线程的堆栈帧以及相关信息。
- b选项显示传递给堆栈跟踪中每个函数的前三个参数。
vs的线程情况
可以看到在这里加锁时,因为被其他线程锁定了,其他线程并没有解锁,就导致这里被阻塞了
f
!cs -l 仅显示死锁的临界区信息。
相关的的线程锁函数
NtWaitForAlertByThreadId
NtWaitForAlertByThreadId
是在 Windows 操作系统中的 ntdll.dll
动态链接库中定义的函数,用于等待指定线程的警告状态。
该函数的原型如下:
cCopy Code NTSTATUS NtWaitForAlertByThreadId( HANDLE ThreadHandle, PLARGE_INTEGER Timeout );
ThreadHandle
:要等待的线程句柄。Timeout
:等待的超时时间。
该函数的作用是使当前线程进入等待状态,直到所指定的线程发出警告通知。警告通常由应用程序自定义的机制触发。
出现在调用堆栈中的 NtWaitForAlertByThreadId
表明当前线程正在等待指定线程发出的警告。
WaitForMultipleObjects
DWORD WaitForMultipleObjects( [in] DWORD nCount, [in] const HANDLE *lpHandles, [in] BOOL bWaitAll, [in] DWORD dwMilliseconds );
2 Id: 2568.4a78 Suspend: 1 Teb: 01bcc000 Unfrozen # ChildEBP RetAddr Args to Child 00 05cffcf4 75b13033 00000003 05830bf0 00000001 ntdll!NtWaitForMultipleObjects+0xc nCount lpHandles bWaitAll # 对应的参数 # 第二个参数是个指针,通过dd查看指针指向的内存数据 :003> dd 05830bf0 05830bf0 00000510 00000518 0000051c 00000000 05830c00 05830c30 00000000 00000000 00000000 05830c10 00000000 00000000 00000000 00000000 05830c20 00000000 00000000 00000000 00000000 05830c30 05830c60 00000000 00000000 00000000 05830c40 00000000 00000000 00000000 00000000 05830c50 00000000 00000000 00000000 00000000 05830c60 05830c90 00000000 00000000 00000000 0:003> !cs 05830bf0 ----------------------------------------- Critical section = 0x05830bf0 (+0x5830BF0) DebugInfo = 0x00000510 LOCKED LockCount = 0xFFFFFEB9 # 这是一个负数 WaiterWoken = Yes OwningThread = 0x00000000 # 没有线程拥有它 RecursionCount = 0x51C LockSemaphore = 0x5830C30 SpinCount = 0x00000000
WaitForSingleObject
DWORD WaitForSingleObject( [in] HANDLE hHandle, [in] DWORD dwMilliseconds );
最终问题定位
程序就是出现了死锁,死锁的原因是window窗口部分代码导致的,子线程调用Windows的SendMessage,导致的主线程阻塞,网上说SendMessage里面其实有一个锁,有这种可能导致主线程阻塞。
CCLOG函数在win32上的实现,里面有调用SendMessage,而我在子线程里面打log,触发了这个大坑
解决办法是MsgWaitForMultipleObjects(),但是我不清楚怎么处理,对Windows编程不太熟悉,这也算是cocos2dx的一个bug