C++ - 如何找出当前线程的创建位置?

Posted

技术标签:

【中文标题】C++ - 如何找出当前线程的创建位置?【英文标题】:C++ - How can I find out where the current thread was created? 【发布时间】:2015-12-30 15:08:26 【问题描述】:

我正在使用 Visual Studio 2010 开发一个巨大的 C++ MFC GUI 应用程序,其中包含大量我不熟悉的代码。

有一个线程被产生了太多次,我不确定它是在哪里产生的,因为有很多代码产生了这个线程。此外,同一线程的代码中有许多创建点。我需要找到哪个创建点启动了当前线程函数。

如何在 Visual Studio 中找到创建线程的位置?

注意:我在调用堆栈窗口中看不到线程的创建位置。

【问题讨论】:

你所说的“相同”线程是什么意思?有问题的线程的独特属性是什么? 对不起,我的意思是同一个线程 id 不是同一个线程。 尝试查找线程pid。查找线程来源可能会有所帮助。 @taha,对不起,我不明白。只有一个具有给定线程 ID 的线程,它不能“产生太多次”。 @SergeyA,是的,实际上只有一个线程。但是有很多线程调用不是分别的,我无法跟踪线程。我只需要找到创建当前线程函数的代码行。 【参考方案1】:

如果可能的话,为用于创建线程的函数创建宏定义,然后在创建后将线程 ID/句柄存储在某个映射中,该映射将包含以下类型对:[ThreadID] -> [__FILE__+__LINE__ ] 。这将允许您检查线程内部的创建位置。

一个更高级的方法是使用 api 钩子,但那是很多编码。因此,您可以使用http://codefromthe70s.org/mhook22.aspx 和挂钩 CreateThread 的 api 挂钩。当您的自定义 CreateThread 函数被执行时,您可以执行原始 CreateThread 并使用其返回的句柄更新地图,如第一段所示。问题是您必须存储调用堆栈数据才能找到执行此调用的位置。您可以为此使用http://www.codeproject.com/Articles/11132/Walking-the-callstack。

即使使用第一个解决方案,您也可能会发现 __FILE__+__LINE__ 没有为您提供足够的信息,并且调用堆栈是必须的。


我用 mhook 制作了一个小型测试应用程序 - 下面是一些可能有用的代码:

typedef HANDLE(WINAPI *CreateThread_t)(LPSECURITY_ATTRIBUTES, SIZE_T, LPTHREAD_START_ROUTINE, LPVOID, DWORD, LPDWORD);
CreateThread_t fCreateThread = (CreateThread_t)GetProcAddress(LoadLibrary(L"Kernel32.dll"), "CreateThread");

HANDLE
WINAPI
MyCreateThread(
  _In_opt_ LPSECURITY_ATTRIBUTES lpThreadAttributes,
  _In_ SIZE_T dwStackSize,
  _In_ LPTHREAD_START_ROUTINE lpStartAddress,
  _In_opt_ __drv_aliasesMem LPVOID lpParameter,
  _In_ DWORD dwCreationFlags,
  _Out_opt_ LPDWORD lpThreadId
  )

  HANDLE hret = fCreateThread(lpThreadAttributes, dwStackSize, lpStartAddress, lpParameter, dwCreationFlags, lpThreadId);
  // Here you can add thread entry for hret with current callstack.
  // You will probably want to create this thread suspended, to make
  // sure it wont get executed before map gets updated. Resume it after
  // map update.
  //if (lpStartAddress == MyThreadProcToMonitor) 
    // log things
  //
  return hret;


int main() 
// This will hook create thread
  Mhook_SetHook((PVOID*)&fCreateThread, MyCreateThread);

  // App logic here

  Mhook_Unhook((PVOID*)&fCreateThread);

【讨论】:

【参考方案2】:

如果允许您稍微更改代码,您可以用一个宏替换线程启动调用,该宏也会记录__FILE____LINE__ 和线程 ID,以便您可以跟踪启动。

【讨论】:

以上是关于C++ - 如何找出当前线程的创建位置?的主要内容,如果未能解决你的问题,请参考以下文章

将程序 (.exe) 作为线程执行 - Window C++

C语言如何终止线程?

如何在不阻塞主线程的情况下使用 join() 创建多个 C++ 线程?

C++并发与多线程 2_线程启动结束,创建线程多种方法,join,detach

找出由运行时间短的程序创建的线程数

线程中的内存范围共享:确保数据不会卡在缓存中