如何使用 WinDBG 临界区和线程列表查找线程 ID?
How can I find thread ID using WinDBG critical section and thread list?
我分析了转储文件以找到锁定的线程,并且我使用 !cs 命令找到了。
DebugInfo = 0x00639610
Critical section = 0x03e210c8 (+0x3E210C8)
LOCKED
LockCount = 0x1
WaiterWoken = No
OwningThread = 0x000017c8
RecursionCount = 0x1
LockSemaphore = 0x5B0
SpinCount = 0x00000000
这个结果意味着ThreadID 0x000017c8获得了临界区。所以我列出了所有线程以使用 ~ 命令查找 threadID 0x000017c8。
0:000> ~
. 0 Id: 2240.1758 Suspend: 0 Teb: 7efdd000 Unfrozen
1 Id: 2240.1d90 Suspend: 0 Teb: 7efda000 Unfrozen
2 Id: 2240.16fc Suspend: 0 Teb: 7efd7000 Unfrozen
3 Id: 2240.1544 Suspend: 0 Teb: 7ef9c000 Unfrozen
4 Id: 2240.2550 Suspend: 0 Teb: 7ef99000 Unfrozen
5 Id: 2240.fd4 Suspend: 0 Teb: 7ef96000 Unfrozen
6 Id: 2240.1b08 Suspend: 0 Teb: 7ef93000 Unfrozen
7 Id: 2240.1958 Suspend: 0 Teb: 7ef90000 Unfrozen
8 Id: 2240.20e8 Suspend: 0 Teb: 7ef8d000 Unfrozen
9 Id: 2240.1bec Suspend: 0 Teb: 7ef8a000 Unfrozen
10 Id: 2240.fb4 Suspend: 0 Teb: 7ef87000 Unfrozen
11 Id: 2240.25c0 Suspend: 0 Teb: 7ef84000 Unfrozen
12 Id: 2240.15b0 Suspend: 0 Teb: 7ef81000 Unfrozen
13 Id: 2240.21a8 Suspend: 0 Teb: 7ef7b000 Unfrozen
14 Id: 2240.1fcc Suspend: 0 Teb: 7ef78000 Unfrozen
但是,没有threadID 0x000017c8。这个转储文件发生了什么?我如何找到线程 ID 0x000017c8?
Kjell Gunnar 是对的:线程 17c8
已因任何原因终止。
这不仅会发生在临界区,也会发生在其他同步对象上。在我的高级调试培训中,我为参与者提供了一个 ManualResetEvent
.
具有类似情况的转储
来源如下:
#include "stdafx.h"
#include <Windows.h>
#include <process.h>
#include <stdio.h>
#include <iostream>
HANDLE threadA;
HANDLE threadB;
HANDLE eventB;
class WorkItem
{
public:
virtual void Initialize()
{
}
};
unsigned int __stdcall initializeWorkitems(void* param)
{
try
{
// Initialize workitems
WorkItem **items = new WorkItem*[2];
items[0] = new WorkItem();
items[1] = NULL;
for (int i = 0; i<2; i++)
{
items[i]->Initialize();
}
// Signal event for second thread to work on work items
SetEvent(eventB);
}
catch(...)
{
// Don't do this
}
return 0;
}
unsigned int __stdcall processWorkitems(void* param)
{
// Wait for work item initialization to complete
WaitForSingleObject(eventB, INFINITE);
// Work on workitems
Sleep(100);
return 0;
}
int _tmain(int argc, _TCHAR* argv[])
{
eventB = CreateEvent(0, 0, 0, 0);
threadA = (HANDLE)_beginthreadex(0, 0, &initializeWorkitems, (void*)0, 0, 0);
threadB = (HANDLE)_beginthreadex(0, 0, &processWorkitems, (void*)0, 0, 0);
WaitForSingleObject(threadA, INFINITE);
WaitForSingleObject(threadB, INFINITE);
CloseHandle(threadA);
CloseHandle(threadB);
CloseHandle(eventB);
return 0;
}
在进程挂起时创建转储。分析的结果应该与您的关键部分相当。 threadA
终止静默,在 catch(...)
块中吃掉 NullPointerException,这样就永远不会释放手动重置事件。
我分析了转储文件以找到锁定的线程,并且我使用 !cs 命令找到了。
DebugInfo = 0x00639610
Critical section = 0x03e210c8 (+0x3E210C8)
LOCKED
LockCount = 0x1
WaiterWoken = No
OwningThread = 0x000017c8
RecursionCount = 0x1
LockSemaphore = 0x5B0
SpinCount = 0x00000000
这个结果意味着ThreadID 0x000017c8获得了临界区。所以我列出了所有线程以使用 ~ 命令查找 threadID 0x000017c8。
0:000> ~
. 0 Id: 2240.1758 Suspend: 0 Teb: 7efdd000 Unfrozen
1 Id: 2240.1d90 Suspend: 0 Teb: 7efda000 Unfrozen
2 Id: 2240.16fc Suspend: 0 Teb: 7efd7000 Unfrozen
3 Id: 2240.1544 Suspend: 0 Teb: 7ef9c000 Unfrozen
4 Id: 2240.2550 Suspend: 0 Teb: 7ef99000 Unfrozen
5 Id: 2240.fd4 Suspend: 0 Teb: 7ef96000 Unfrozen
6 Id: 2240.1b08 Suspend: 0 Teb: 7ef93000 Unfrozen
7 Id: 2240.1958 Suspend: 0 Teb: 7ef90000 Unfrozen
8 Id: 2240.20e8 Suspend: 0 Teb: 7ef8d000 Unfrozen
9 Id: 2240.1bec Suspend: 0 Teb: 7ef8a000 Unfrozen
10 Id: 2240.fb4 Suspend: 0 Teb: 7ef87000 Unfrozen
11 Id: 2240.25c0 Suspend: 0 Teb: 7ef84000 Unfrozen
12 Id: 2240.15b0 Suspend: 0 Teb: 7ef81000 Unfrozen
13 Id: 2240.21a8 Suspend: 0 Teb: 7ef7b000 Unfrozen
14 Id: 2240.1fcc Suspend: 0 Teb: 7ef78000 Unfrozen
但是,没有threadID 0x000017c8。这个转储文件发生了什么?我如何找到线程 ID 0x000017c8?
Kjell Gunnar 是对的:线程 17c8
已因任何原因终止。
这不仅会发生在临界区,也会发生在其他同步对象上。在我的高级调试培训中,我为参与者提供了一个 ManualResetEvent
.
来源如下:
#include "stdafx.h"
#include <Windows.h>
#include <process.h>
#include <stdio.h>
#include <iostream>
HANDLE threadA;
HANDLE threadB;
HANDLE eventB;
class WorkItem
{
public:
virtual void Initialize()
{
}
};
unsigned int __stdcall initializeWorkitems(void* param)
{
try
{
// Initialize workitems
WorkItem **items = new WorkItem*[2];
items[0] = new WorkItem();
items[1] = NULL;
for (int i = 0; i<2; i++)
{
items[i]->Initialize();
}
// Signal event for second thread to work on work items
SetEvent(eventB);
}
catch(...)
{
// Don't do this
}
return 0;
}
unsigned int __stdcall processWorkitems(void* param)
{
// Wait for work item initialization to complete
WaitForSingleObject(eventB, INFINITE);
// Work on workitems
Sleep(100);
return 0;
}
int _tmain(int argc, _TCHAR* argv[])
{
eventB = CreateEvent(0, 0, 0, 0);
threadA = (HANDLE)_beginthreadex(0, 0, &initializeWorkitems, (void*)0, 0, 0);
threadB = (HANDLE)_beginthreadex(0, 0, &processWorkitems, (void*)0, 0, 0);
WaitForSingleObject(threadA, INFINITE);
WaitForSingleObject(threadB, INFINITE);
CloseHandle(threadA);
CloseHandle(threadB);
CloseHandle(eventB);
return 0;
}
在进程挂起时创建转储。分析的结果应该与您的关键部分相当。 threadA
终止静默,在 catch(...)
块中吃掉 NullPointerException,这样就永远不会释放手动重置事件。