24 ThreadName
Setting the name of the thread in the code allows you to see the thread name in debugging tools such as Visual Studio. This is very convenient when there are lots of threads running in the process.
See:
- C++ set thread name under Linux/Windows for multi-thread debugging
- How to: Set a Thread Name in Native Code in Microsoft Docs.
It seems that
SetThreadDescriptionis better than the technique of throwing an exception in Visual Studio 2017 version 15.6 and later versions, because the thread names are visible when debugging in Visual Studio, regardless of whether or not the debugger was attached to the process at the time thatSetThreadDescriptionis invoked. - Changing the thread name on C++11 on GitHub
- pthread_setname_np(3) — Linux manual page. This says the thread name is a meaningful C language string, whose length is restricted to 16 characters, including the terminating null byte ('\0')
- See how to set a threadname in MacOSX on Stack Overflow.
ThreadName.h
// ThreadName.h
//
// Author David Barrett-Lennard
// (C)opyright Cedanet Pty Ltd
#pragma once
#ifndef Ceda_cxThread_ThreadName_H
#define Ceda_cxThread_ThreadName_H
#include "cxThread.h"
#include "Ceda/cxUtils/xstring.h"
namespace ceda
{
cxThread_API void SetThreadName(const char* threadName);
inline void SetThreadName(const xstring& threadName)
{
SetThreadName(threadName.c_str());
}
} // namespace ceda
#endif
ThreadName.cpp
// ThreadName.cpp
//
// Author David Barrett-Lennard
// (C)opyright Cedanet Pty Ltd
#include "ThreadName.h"
#ifdef _MSC_VER
#include "Ceda/cxUtils/MsWindows.h"
#else
#include <pthread.h>
#endif
namespace ceda
{
#if defined _WIN32 || defined __CYGWIN__
extern "C" typedef HRESULT (WINAPI *t_SetThreadDescription)( HANDLE, PCWSTR );
#endif
cxThread_API void SetThreadName(const char* name)
{
#if defined _WIN32 || defined __CYGWIN__
static auto SetThreadDescription = (t_SetThreadDescription) GetProcAddress( GetModuleHandleA( "kernel32.dll" ), "SetThreadDescription" );
if (SetThreadDescription)
{
wchar_t buf[256];
mbstowcs( buf, name, 256 );
SetThreadDescription( GetCurrentThread(), buf );
}
else
{
#if defined _MSC_VER
#pragma pack(push,8)
struct THREADNAME_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.
};
#pragma pack(pop)
THREADNAME_INFO info{ 0x1000, name, (DWORD)-1, 0 };
__try
{
RaiseException( 0x406D1388, 0, sizeof(info)/sizeof(ULONG_PTR), (ULONG_PTR*)&info );
}
__except(EXCEPTION_EXECUTE_HANDLER)
{
}
#endif
}
#elif defined _GNU_SOURCE && !defined __EMSCRIPTEN__ && !defined __CYGWIN__
char sizeLimitedName[16];
strncpy(sizeLimitedName, name, 15);
#ifdef __APPLE__
pthread_setname_np(sizeLimitedName);
#else
pthread_setname_np(pthread_self(), sizeLimitedName);
#endif
#endif
}
} // namespace ceda