自己的底层代码库(八)——获取函数调用堆栈

今天放上一个工具类,用来获取当前线程/所有线程的当前函数调用堆栈

主要是为了方便用于在打log时,可以将调用堆栈一起输出到文件当中

PS:想打出正确的log是依赖于PDB文件的

类似于VS的向output窗口输出$CALLSTACK


主要用了dbghelp的一些API

参考了:

http://www.cnblogs.com/zplutor/archive/2011/04/23/2025549.html

http://www.codeproject.com/KB/threads/StackWalker/StackWalker.zip


剥离了一些不需要的功能,只提供两个接口

//打印当前进程下 指定线程号的线程调用堆栈

BOOL GetCallstack(std::vector<std::string>& callStacks, DWORD dwThreadId);

//打印当前进程下 所有线程的调用堆栈
BOOL GetCallstack(std::vector<std::string>& callStacks);


下面直接上代码:

CStackWalker.h:

#ifndef _CStackWalker_h_
#define _CStackWalker_h_

#include <windows.h>

#include <map>
#include <vector>

#include <tchar.h>

#include <DbgHelp.h>
#include <tlhelp32.h>

#undef MODULEENTRY32
#undef PMODULEENTRY32
#undef LPMODULEENTRY32

class StackWalkerInterface
{
public:
	StackWalkerInterface();

	~StackWalkerInterface();

	// SymInitialize()
	typedef BOOL (__stdcall *fpSymInitialize)(
		IN HANDLE hProcess,
		IN PSTR UserSearchPath, 
		IN BOOL fInvadeProcess
		);
	fpSymInitialize m_fpSymInitialize;

	// SymCleanup()
	typedef BOOL (__stdcall *fpSymCleanup)(
		IN HANDLE hProcess
		);
	fpSymCleanup m_fpSymCleanup;

	// StackWalk64()
	typedef BOOL (__stdcall *fpStackWalk64)(
		DWORD MachineType, 
		HANDLE hProcess,
		HANDLE hThread, 
		LPSTACKFRAME64 StackFrame, 
		PVOID ContextRecord,
		PREAD_PROCESS_MEMORY_ROUTINE64 ReadMemoryRoutine,
		PFUNCTION_TABLE_ACCESS_ROUTINE64 FunctionTableAccessRoutine,
		PGET_MODULE_BASE_ROUTINE64 GetModuleBaseRoutine,
		PTRANSLATE_ADDRESS_ROUTINE64 TranslateAddress
		);
	fpStackWalk64 m_fpStackWalk64;

	// SymSetContext()
	typedef BOOL (__stdcall *fpSymSetContext)(
		HANDLE hProcess,
		PIMAGEHLP_STACK_FRAME StackFrame,
		PIMAGEHLP_CONTEXT Context
		);
	fpSymSetContext m_fpSymSetContext;

	// SymEnumSymbols()
	typedef BOOL (__stdcall *fpSymEnumSymbols)(
		HANDLE hProcess,
		ULONG64 BaseOfDll,
		PCTSTR Mask,
		PSYM_ENUMERATESYMBOLS_CALLBACK EnumSymbolsCallback,
		PVOID UserContext
		);
	fpSymEnumSymbols m_fpSymEnumSymbols;

	// SymGetOptions()
	typedef DWORD (__stdcall *fpSymGetOptions)();
	fpSymGetOptions m_fpSymGetOptions;

	// SymSetOptions()
	typedef DWORD (__stdcall *fpSymSetOptions)(IN DWORD SymOptions);
	fpSymSetOptions m_fpSymSetOptions;

	// SymFunctionTableAccess64()
	typedef PVOID (__stdcall *fpSymFunctionTableAccess64)(
		HANDLE hProcess,
		DWORD64 AddrBase
		);
	fpSymFunctionTableAccess64 m_fpSymFunctionTableAccess64;

	// SymGetLineFromAddr64()
	typedef BOOL (__stdcall *fpSymGetLineFromAddr64)(
		IN HANDLE hProcess,
		IN DWORD64 dwAddr,
		OUT PDWORD pdwDisplacement,
		OUT PIMAGEHLP_LINE64 Line
		);
	fpSymGetLineFromAddr64 m_fpSymGetLineFromAddr64;

	// SymGetModuleBase64()
	typedef DWORD64 (__stdcall *fpSymGetModuleBase64)(
		IN HANDLE hProcess,
		IN DWORD64 dwAddr
		);
	fpSymGetModuleBase64 m_fpSymGetModuleBase64;

	// SymGetSymFromAddr64()
	typedef BOOL (__stdcall *fpSymGetSymFromAddr64)(
		IN HANDLE hProcess,
		IN DWORD64 dwAddr,
		OUT PDWORD64 pdwDisplacement,
		OUT PIMAGEHLP_SYMBOL64 Symbol );
	fpSymGetSymFromAddr64 m_fpSymGetSymFromAddr64;

	// UnDecorateSymbolName()
	typedef DWORD (__stdcall WINAPI *fpUnDecorateSymbolName)(
		PCSTR DecoratedName,
		PSTR UnDecoratedName,
		DWORD UndecoratedLength,
		DWORD Flags );
	fpUnDecorateSymbolName m_fpUnDecorateSymbolName;

	// SymLoadModule64()
	typedef DWORD64 (__stdcall *fpSymLoadModule64)(
		IN HANDLE hProcess,
		IN HANDLE hFile,
		IN PSTR ImageName,
		IN PSTR ModuleName,
		IN DWORD64 BaseOfDll,
		IN DWORD SizeOfDll
		);
	fpSymLoadModule64 m_fpSymLoadModule64;

	
	
	// CreateToolhelp32Snapshot()
	typedef HANDLE (__stdcall *fpCreateToolhelp32Snapshot)(
		DWORD dwFlags, 
		DWORD th32ProcessID
		);
	fpCreateToolhelp32Snapshot m_fpCreateToolhelp32Snapshot;
	
	// Module32First()
	typedef BOOL (__stdcall *fpModule32First)(
		HANDLE hSnapshot, 
		LPMODULEENTRY32 lpme
		);
	fpModule32First m_fpModule32First;

	// Module32Next()
	typedef BOOL (__stdcall *fpModule32Next)(
		HANDLE hSnapshot, 
		LPMODULEENTRY32 lpme
		);
	fpModule32Next m_fpModule32Next;

	// Thread32First()
	typedef BOOL (__stdcall *fpThread32First)(
		HANDLE hSnapshot, 
		LPTHREADENTRY32 lpme
		);
	fpThread32First m_fpThread32First;

	// Thread32Next()
	typedef BOOL (__stdcall *fpThread32Next)(
		HANDLE hSnapshot, 
		LPTHREADENTRY32 lpme
		);
	fpThread32Next m_fpThread32Next;

	bool Init();
	bool CanUse();
	
private:
#ifdef UNICODE
	HMODULE LoadDll(const WCHAR *pDllName);
#else
	HMODULE LoadDll(const char *pDllName);
#endif	
	FARPROC LoadAPI(HMODULE dllHandle, const char *pAPIName);

	HMODULE m_hDbhHelp;
	HMODULE m_hToolhelp;

	bool m_bCanUse;
};


const DWORD STACKWALK_MAX_NAMELEN = 1024;

class CStackWalker
{
public:
	CStackWalker(void);
	~CStackWalker(void);

	BOOL GetCallstack(std::vector<std::string>& callStacks, DWORD dwThreadId);
	BOOL GetCallstack(std::vector<std::string>& callStacks);

private:
	StackWalkerInterface m_swi;

	HANDLE m_hProcess;
	DWORD m_dwProcessId;
	HANDLE m_hThread;
	DWORD m_dwThreadId;

	//当前堆栈信息
	char m_StackInfo[STACKWALK_MAX_NAMELEN];

	//模块基址-名称映射表
	std::map<DWORD64, std::string> m_ModuleList;
	BOOL GetModuleList();
};

extern CStackWalker g_StackWalker;

#endif

CStackWalker.cpp:

#include "CStackWalker.h"

StackWalkerInterface::StackWalkerInterface()
{
	m_hDbhHelp = NULL;
	m_hToolhelp = NULL;

	m_fpCreateToolhelp32Snapshot = NULL;
	m_fpModule32First = NULL;
	m_fpModule32Next = NULL;
	m_fpThread32First = NULL;
	m_fpThread32Next = NULL;

	m_fpSymInitialize = NULL;
	m_fpSymCleanup = NULL;

	m_fpStackWalk64 = NULL;
	m_fpSymSetContext = NULL;
	m_fpSymEnumSymbols = NULL;

	m_fpSymGetOptions = NULL;
	m_fpSymSetOptions = NULL;

	m_fpSymGetModuleBase64 = NULL;

	m_fpSymFunctionTableAccess64 = NULL;

	m_fpSymGetLineFromAddr64 = NULL;

	m_fpSymGetSymFromAddr64 = NULL;

	m_fpSymLoadModule64 = NULL;

	m_fpUnDecorateSymbolName = NULL;

	m_bCanUse = false;
}

StackWalkerInterface::~StackWalkerInterface()
{
	if (m_hDbhHelp != NULL)
	{
		FreeLibrary(m_hDbhHelp);
		m_hDbhHelp = NULL;
	}
	if (m_hToolhelp != NULL)
	{
		FreeLibrary(m_hToolhelp);
		m_hToolhelp = NULL;
	}
}

#ifdef UNICODE
HMODULE StackWalkerInterface::LoadDll(const WCHAR *pDllName)
#else
HMODULE StackWalkerInterface::LoadDll(const char *pDllName)
#endif
{
	HMODULE dllHandle = LoadLibrary(pDllName);
	if (NULL != dllHandle)
	{
		return dllHandle;
	}
	else
	{
		printf("StackWalkerInterface LoadLibrary \"%s\" Error code 0x%08x!\n", pDllName, GetLastError());
		return NULL;
	}
}

FARPROC StackWalkerInterface::LoadAPI(HMODULE dllHandle, const char *pAPIName)
{
	FARPROC apiAddr = GetProcAddress(dllHandle, pAPIName);
	if (NULL != apiAddr)
	{
		return apiAddr;
	}
	else
	{
		printf("StackWalkerInterface GetProcAddress \"%s\" Error code 0x%08x!\n", pAPIName, GetLastError());
		return NULL;
	}
}

bool StackWalkerInterface::Init()
{
	bool res = false;
	
	// 加载dbghelp.dll >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
	m_hDbhHelp = LoadDll(_T("dbghelp.dll"));
	if (NULL == m_hDbhHelp)
	{
		return false;
	}
	
	m_fpSymInitialize = (fpSymInitialize) LoadAPI(m_hDbhHelp, "SymInitialize" );
	if (NULL == m_fpSymInitialize)
	{
		return false;
	}
	
	m_fpSymCleanup = (fpSymCleanup) LoadAPI(m_hDbhHelp, "SymCleanup" );
	if (NULL == m_fpSymCleanup)
	{
		return false;
	}

	m_fpStackWalk64 = (fpStackWalk64) LoadAPI(m_hDbhHelp, "StackWalk64" );
	if (NULL == m_fpStackWalk64)
	{
		return false;
	}

	m_fpSymSetContext = (fpSymSetContext) LoadAPI(m_hDbhHelp, "SymSetContext" );
	if (NULL == m_fpSymSetContext)
	{
		return false;
	}

	m_fpSymEnumSymbols = (fpSymEnumSymbols) LoadAPI(m_hDbhHelp, "SymEnumSymbols" );
	if (NULL == m_fpSymEnumSymbols)
	{
		return false;
	}

	m_fpSymGetOptions = (fpSymGetOptions) LoadAPI(m_hDbhHelp, "SymGetOptions" );
	if (NULL == m_fpSymGetOptions)
	{
		return false;
	}

	m_fpSymSetOptions = (fpSymSetOptions) LoadAPI(m_hDbhHelp, "SymSetOptions" );
	if (NULL == m_fpSymSetOptions)
	{
		return false;
	}

	m_fpSymFunctionTableAccess64 = (fpSymFunctionTableAccess64) LoadAPI(m_hDbhHelp, "SymFunctionTableAccess64" );
	if (NULL == m_fpSymFunctionTableAccess64)
	{
		return false;
	}

	m_fpSymGetLineFromAddr64 = (fpSymGetLineFromAddr64) LoadAPI(m_hDbhHelp, "SymGetLineFromAddr64" );
	if (NULL == m_fpSymGetLineFromAddr64)
	{
		return false;
	}

	m_fpSymGetModuleBase64 = (fpSymGetModuleBase64) LoadAPI(m_hDbhHelp, "SymGetModuleBase64" );
	if (NULL == m_fpSymGetModuleBase64)
	{
		return false;
	}

	m_fpSymGetSymFromAddr64 = (fpSymGetSymFromAddr64) LoadAPI(m_hDbhHelp, "SymGetSymFromAddr64" );
	if (NULL == m_fpSymGetSymFromAddr64)
	{
		return false;
	}

	m_fpUnDecorateSymbolName = (fpUnDecorateSymbolName) LoadAPI(m_hDbhHelp, "UnDecorateSymbolName" );
	if (NULL == m_fpUnDecorateSymbolName)
	{
		return false;
	}

	m_fpSymLoadModule64 = (fpSymLoadModule64) LoadAPI(m_hDbhHelp, "SymLoadModule64" );
	if (NULL == m_fpSymLoadModule64)
	{
		return false;
	}

	// 加载kernel32.dll >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
	m_hToolhelp = LoadDll(_T("kernel32.dll"));
	if (NULL == m_hToolhelp)
	{
		return false;
	}
	
	m_fpCreateToolhelp32Snapshot = (fpCreateToolhelp32Snapshot)LoadAPI(m_hToolhelp, "CreateToolhelp32Snapshot");
	if (NULL == m_fpCreateToolhelp32Snapshot)
	{
		return false;
	}

	m_fpModule32First = (fpModule32First) LoadAPI(m_hToolhelp, "Module32First");
	if (NULL == m_fpModule32First)
	{
		return false;
	}

	m_fpModule32Next = (fpModule32Next) LoadAPI(m_hToolhelp, "Module32Next");
	if (NULL == m_fpModule32Next)
	{
		return false;
	}

	m_fpThread32First = (fpThread32First) LoadAPI(m_hToolhelp, "Thread32First");
	if (NULL == m_fpThread32First)
	{
		return false;
	}

	m_fpThread32Next = (fpThread32Next) LoadAPI(m_hToolhelp, "Thread32Next");
	if (NULL == m_fpThread32Next)
	{
		return false;
	}

	m_bCanUse = true;
	return true;
}

bool StackWalkerInterface::CanUse()
{
	return m_bCanUse;
}

CStackWalker::CStackWalker(void)
{
	m_hProcess = GetCurrentProcess();
	m_dwProcessId = GetCurrentProcessId();
	
	BOOL res = m_swi.Init();
	if (!res)
	{
		printf("StackWalkerInterface Init() Error!\n");
		return;
	}

	res = m_swi.m_fpSymInitialize(m_hProcess, NULL, TRUE);
	if (!res)
	{
		printf("SymInitialize() Error code 0x%08x!\n", GetLastError());
		return;
	}

	DWORD symOptions = m_swi.m_fpSymGetOptions();
	symOptions |= SYMOPT_LOAD_LINES;
	symOptions |= SYMOPT_FAIL_CRITICAL_ERRORS;
	symOptions = m_swi.m_fpSymSetOptions(symOptions);

	GetModuleList();
}

CStackWalker::~CStackWalker(void)
{
	m_swi.m_fpSymCleanup(m_hProcess);
	m_ModuleList.clear();
}

BOOL CStackWalker::GetModuleList()
{
	m_ModuleList.clear();

	HANDLE hSnap = INVALID_HANDLE_VALUE;
	hSnap = m_swi.m_fpCreateToolhelp32Snapshot(TH32CS_SNAPMODULE, m_dwProcessId);
	if (hSnap == INVALID_HANDLE_VALUE)
	{
		printf("CreateToolhelp32Snapshot() Error code 0x%08x!\n", GetLastError());
		return FALSE;
	}

	MODULEENTRY32 me;
	memset(&me, 0, sizeof(me));
	me.dwSize = sizeof(me);

	BOOL res = FALSE;
	int cnt = 0;
	res = m_swi.m_fpModule32First(hSnap, &me);
	while (res)
	{
		m_swi.m_fpSymLoadModule64(m_hProcess, 0, me.szExePath, me.szModule, 
			(DWORD64) me.modBaseAddr, me.modBaseSize);

		std::string name = me.szModule;
		m_ModuleList[(DWORD64)me.modBaseAddr] = name;
		
		cnt++;
		res = m_swi.m_fpModule32Next( hSnap, &me );
	}

	CloseHandle(hSnap);

	if (cnt > 0)
	{
		res = TRUE;
	}

	return res;
}

BOOL CStackWalker::GetCallstack(std::vector<std::string>& callStacks, DWORD dwThreadId)
{
	if (!m_swi.CanUse())
	{
		return FALSE;
	}

	HANDLE hSnap = m_swi.m_fpCreateToolhelp32Snapshot(TH32CS_SNAPALL, m_dwProcessId);
	if (hSnap == INVALID_HANDLE_VALUE)
	{
		printf("CreateToolhelp32Snapshot() Error code 0x%08x!\n", GetLastError());
		return FALSE;
	}
	
	HANDLE hThread = OpenThread(THREAD_ALL_ACCESS, FALSE, dwThreadId);
	DWORD hCurrThreadId = ::GetCurrentThreadId();
	if (hThread != NULL)
	{
		CONTEXT context;
		if (dwThreadId != hCurrThreadId)
		{
			SuspendThread(hThread);
			memset(&context, 0, sizeof(CONTEXT));
			context.ContextFlags = CONTEXT_FULL;
			if (!GetThreadContext(hThread, &context))
			{
				ResumeThread(hThread);
				return FALSE;
			}
		}
		else
		{
			memset(&context, 0, sizeof(CONTEXT));
			context.ContextFlags = CONTEXT_FULL;
			__asm    call x 
			__asm x: pop eax 
			__asm    mov context.Eip, eax 
			__asm    mov context.Ebp, ebp 
			__asm    mov context.Esp, esp 
		}

		STACKFRAME64 stackframe;
		memset(&stackframe, 0, sizeof(stackframe));
		DWORD imageType;

#ifdef _M_IX86
		imageType = IMAGE_FILE_MACHINE_I386;
		stackframe.AddrPC.Offset = context.Eip;
		stackframe.AddrPC.Mode = AddrModeFlat;
		stackframe.AddrFrame.Offset = context.Ebp;
		stackframe.AddrFrame.Mode = AddrModeFlat;
		stackframe.AddrStack.Offset = context.Esp;
		stackframe.AddrStack.Mode = AddrModeFlat;
#elif _M_X64
		imageType = IMAGE_FILE_MACHINE_AMD64;
		stackframe.AddrPC.Offset = context.Rip;
		stackframe.AddrPC.Mode = AddrModeFlat;
		stackframe.AddrFrame.Offset = context.Rsp;
		stackframe.AddrFrame.Mode = AddrModeFlat;
		stackframe.AddrStack.Offset = context.Rsp;
		stackframe.AddrStack.Mode = AddrModeFlat;
#else
#error "Not Supported!"
#endif

		char sysbuff[sizeof(IMAGEHLP_SYMBOL64) + STACKWALK_MAX_NAMELEN];
		IMAGEHLP_SYMBOL64 *pSym = (IMAGEHLP_SYMBOL64 *)sysbuff;
		memset(pSym, 0x00, sizeof(IMAGEHLP_SYMBOL64) + STACKWALK_MAX_NAMELEN);
		pSym->SizeOfStruct = sizeof(IMAGEHLP_SYMBOL64);
		pSym->MaxNameLength = STACKWALK_MAX_NAMELEN;

		IMAGEHLP_LINE64 line;
		memset(&line, 0x00, sizeof(line));
		line.SizeOfStruct = sizeof(line);

		while (true)
		{
			if (!m_swi.m_fpStackWalk64(imageType, m_hProcess, hThread, &stackframe, &context, 
				NULL, m_swi.m_fpSymFunctionTableAccess64, m_swi.m_fpSymGetModuleBase64, NULL) )
			{
				printf("StackWalk64() Error code 0x%08x!\n", GetLastError());
				return FALSE;
			}

			if (stackframe.AddrPC.Offset == stackframe.AddrReturn.Offset)
			{
				break;
			}
			
			if (stackframe.AddrPC.Offset != 0)
			{
				memset(m_StackInfo, 0x00, sizeof(char) * STACKWALK_MAX_NAMELEN);

				//函数对应的模块名 查m_ModuleList表
				DWORD64 moduleBase = m_swi.m_fpSymGetModuleBase64(m_hProcess, stackframe.AddrPC.Offset);
				std::map<DWORD64, std::string>::iterator module = m_ModuleList.find(moduleBase);
				if (module != m_ModuleList.end())
				{
					const char *name = module->second.c_str();
					strcat_s(m_StackInfo, STACKWALK_MAX_NAMELEN, name);
				}
				else
				{
					strcat_s(m_StackInfo, STACKWALK_MAX_NAMELEN, "unknow module");
				}
				strcat_s(m_StackInfo, STACKWALK_MAX_NAMELEN, ": ");

				//函数对应的代码文件 以及行号
				DWORD dwDisplacementFromLine;
				if (m_swi.m_fpSymGetLineFromAddr64(m_hProcess, stackframe.AddrPC.Offset, &dwDisplacementFromLine, &line))
				{
					char name[50] = {0};
					_itoa_s(line.LineNumber, name, 50, 10);
					strcat_s(m_StackInfo, STACKWALK_MAX_NAMELEN, line.FileName);
					strcat_s(m_StackInfo, STACKWALK_MAX_NAMELEN, "(");
					strcat_s(m_StackInfo, STACKWALK_MAX_NAMELEN, name);
					strcat_s(m_StackInfo, STACKWALK_MAX_NAMELEN, ")");
				}
				else
				{
					strcat_s(m_StackInfo, STACKWALK_MAX_NAMELEN, "unknow file");
				}
				strcat_s(m_StackInfo, STACKWALK_MAX_NAMELEN, ": ");

				//函数名
				DWORD64 dwDisplacementFromFunc;
				if (m_swi.m_fpSymGetSymFromAddr64(m_hProcess, stackframe.AddrPC.Offset, &dwDisplacementFromFunc, pSym))
				{
					if(pSym->Name[0] == '?')
					{
						//修饰名 -> 函数签名
						char name[STACKWALK_MAX_NAMELEN] = {0};
						m_swi.m_fpUnDecorateSymbolName(pSym->Name, name, STACKWALK_MAX_NAMELEN, UNDNAME_NAME_ONLY);
						strcat_s(m_StackInfo, STACKWALK_MAX_NAMELEN, name);
					}
					else
					{
						strcat_s(m_StackInfo, STACKWALK_MAX_NAMELEN, pSym->Name);
					}
				}
				else
				{
					strcat_s(m_StackInfo, STACKWALK_MAX_NAMELEN, "unknow func");
				}
				strcat_s(m_StackInfo, STACKWALK_MAX_NAMELEN, ": ");
	
				std::string oneCallStack = m_StackInfo;
				callStacks.push_back(oneCallStack);
			}

			if (stackframe.AddrReturn.Offset == 0)
			{
				break;
			}
		}

		if (dwThreadId != hCurrThreadId)
		{
			ResumeThread(hThread);
		}
		CloseHandle(hThread);

		callStacks.push_back("\n");
	}

	CloseHandle(hSnap);
	return TRUE;
}

BOOL CStackWalker::GetCallstack(std::vector<std::string>& callStacks)
{
	if (!m_swi.CanUse())
	{
		return FALSE;
	}

	HANDLE hSnap = m_swi.m_fpCreateToolhelp32Snapshot(TH32CS_SNAPALL, m_dwProcessId);
	if (hSnap == INVALID_HANDLE_VALUE)
	{
		return FALSE;
	}

	THREADENTRY32 te;
	memset(&te, 0, sizeof(te));
	te.dwSize = sizeof(te);
	BOOL res = m_swi.m_fpThread32First(hSnap, &te);
	while (res)
	{
		if (te.th32OwnerProcessID == m_dwProcessId)
		{
			GetCallstack(callStacks, te.th32ThreadID);
		}
		res = m_swi.m_fpThread32Next(hSnap, &te);
	}

	CloseHandle(hSnap);

	return TRUE;
}

CStackWalker g_StackWalker;

测试程序:

创建两个线程,每个线程里面进行FunA跟FunB的循环调用,线程执行1s后打印当前进程下所有线程的当前调用堆栈

#include "CStackWalker.h"

DWORD WINAPI Run(LPVOID lpParam);
void FunB();
void FunA(int a);

int _tmain(int argc, _TCHAR* argv[])
{
	HANDLE hThread[2] = {0};
	for (int i = 0; i < 2; i++)
	{
		hThread[i] = CreateThread(NULL, 0, Run, 0, 0, NULL);
	}

	Sleep(1000);

	std::vector<std::string> callStacks;
	g_StackWalker.GetCallstack(callStacks);
	for (int i = 0; i < callStacks.size(); i++)
	{
		printf("%s\n", callStacks[i].c_str());
	}

	return 0;
}

void FunB()
{
	Sleep(100);
	FunA(rand());
}

void FunA(int a)
{
	Sleep(100);
	FunB();

}

DWORD WINAPI Run(LPVOID lpParam)
{
	FunB();
	return 0;
}

测试结果



  • 1
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 5
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值