std :: thread - 命名你的线程

时间:2012-04-12 10:12:13

标签: c++ multithreading c++11

新的C ++有这个std :: thread类型。奇迹般有效。 现在我想给每个线程一个名称以便更容易调试(比如java允许你)。 使用pthreads我会这样做:

pthread_setname_np(pthread_self(), "thread_name");

但我怎么能用c ++ 0x做到这一点? 我知道它在Linux系统下使用pthreads,但我想让我的应用程序可移植。它有可能吗?

5 个答案:

答案 0 :(得分:29)

这样做的一种便携方式是维护一个名称映射,由thread::get_id()获取的线程ID来键入。或者,如评论中所建议的,如果您只需要从帖子中访问该名称,则可以使用thread_local变量。

如果您不需要可移植性,那么您可以从pthread_t获取基础thread::native_handle()并执行您喜欢的任何特定于平台的恶作剧。请注意,线程命名函数上的_np表示“not posix”,因此不保证它们在所有pthreads实现上都可用。

答案 1 :(得分:20)

试图制作一个包装器来处理许多Linux和Windows。请根据需要进行编辑。

#ifdef _WIN32
#include <windows.h>
const DWORD MS_VC_EXCEPTION=0x406D1388;

#pragma pack(push,8)
typedef struct tagTHREADNAME_INFO
{
   DWORD dwType; // Must be 0x1000.
   LPCSTR szName; // Pointer to name (in user addr space).
   DWORD dwThreadID; // Thread ID (-1=caller thread).
   DWORD dwFlags; // Reserved for future use, must be zero.
} THREADNAME_INFO;
#pragma pack(pop)


void SetThreadName(uint32_t dwThreadID, const char* threadName)
{

  // DWORD dwThreadID = ::GetThreadId( static_cast<HANDLE>( t.native_handle() ) );

   THREADNAME_INFO info;
   info.dwType = 0x1000;
   info.szName = threadName;
   info.dwThreadID = dwThreadID;
   info.dwFlags = 0;

   __try
   {
      RaiseException( MS_VC_EXCEPTION, 0, sizeof(info)/sizeof(ULONG_PTR), (ULONG_PTR*)&info );
   }
   __except(EXCEPTION_EXECUTE_HANDLER)
   {
   }
}
void SetThreadName( const char* threadName)
{
    SetThreadName(GetCurrentThreadId(),threadName);
}

void SetThreadName( std::thread* thread, const char* threadName)
{
    DWORD threadId = ::GetThreadId( static_cast<HANDLE>( thread->native_handle() ) );
    SetThreadName(threadId,threadName);
}

#else
void SetThreadName(std::thread* thread, const char* threadName)
{
   auto handle = thread->native_handle();
   pthread_setname_np(handle,threadName);
}


#include <sys/prctl.h>
void SetThreadName( const char* threadName)
{
  prctl(PR_SET_NAME,threadName,0,0,0);
}

#endif

答案 2 :(得分:9)

您可以使用std::thread::native_handle来获取底层实现定义的线程。本机没有标准功能。

您可以找到示例here

答案 3 :(得分:4)

对于windows [调试器],您可以轻松使用“普通”方法; http://msdn.microsoft.com/en-gb/library/xcb2z8hs.aspx

只需要你可以通过

获得的线程ID
#include <windows.h>
DWORD ThreadId = ::GetThreadId( static_cast<HANDLE>( mThread.native_handle() ) );

答案 4 :(得分:2)

我在两个系统中都看到过这种情况,这个系统早于c ++ 11(我们基本上发明了我们自己的Thread类,它与std :: thread非常相似),而且是我最近写的一个。

基本上,池确实将std :: thread 2层放下 - 你有一个PoolThread类,它包含一个std :: thread加上元数据,比如它的名称,ID等,以及将它链接到它的控制的控制结构池和ThreadPool本身。您希望在大多数线程代码中使用线程池有以下几个原因:
1)您可以隐藏所有显式的“detach”,“join”,从用户开始std :: thread构建等的线程。这使得更安全和更安全清洁代码。
2)更好的资源管理:太多线程会使性能下降甚至超过太少。精心打造的池可以执行高级操作,例如自动负载平衡和清理挂起或死锁线程。
3)线程重用:通过在自己的线程上运行每个并行任务,std :: thread本身最容易使用。但线程创建&amp;破坏是昂贵的,如果你不小心,很容易淹没并行处理的速度提升。因此,通常使用池线程从队列中提取工作任务并且仅在接收到某些信号后退出更有意义。
4)错误处理:std :: thread只是一个执行上下文。如果您在其上运行的任务抛出未处理的异常或std :: thread ITSELF失败,则该进程将在那里崩溃。要做容错多线程,你需要一个Pool或类似的东西,可以快速捕获这些东西,并至少在进程死亡之前发出有意义的错误消息。