Naming threads in Win32 And .Net


When you are debugging an application with multiple threads it can be handy to have a better name than just the thread id.  This is simple to do in managed code.  There is a property on the Thread object that you can set.  It is also possible to do this for native code. However, there is simply no way you will ever discover it unless someone points you to the difficult to find docs.  I knew about the feature and still missed the docs the first time I looked for them!


 


For completness, here is the managed version: Setting a Thread Name (Managed).


The more interesting one is the native version: Setting a Thread Name (Unmanaged) (There is a typo in the documentation's code; 'except' should be '__except'. I've included a corrected copy below.)


 


The native method of setting the thread name is implemented by raising an SEH exception that is continued.  If you go to the docs on RaiseException you'll see part of the reason for this strange mechanism.  An attached native debugger will get a 'first chance' notification of the exception.  Raising an exception is precisely what you need to do to get the native debugger's attention. The one raised here (0x406D1388) is recognized by VS (and WinDbg).


 


Note: If anything in your process installs a vectored exception handler, that handler will not be called on this exception code when the VS debugger is attached.  The VS debugger always handles this exception code and continues execution, preventing any further handlers.  In WinDbg you can go to Debug/Event Filters and set the "Visual C++ exception" to be disabled.  With that setting, your vectored exception handler will get a shot at 0x406D1388 while WinDbg is debugging it.

//
// Usage: SetThreadName (-1, "MainThread");
//
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;

void SetThreadName( DWORD dwThreadID, LPCSTR szThreadName)
{
THREADNAME_INFO info;
info.dwType = 0x1000;
info.szName = szThreadName;
info.dwThreadID = dwThreadID;
info.dwFlags = 0;

__try
{
RaiseException( 0x406D1388, 0, sizeof(info)/sizeof(DWORD), (DWORD*)&info );
}
__except(EXCEPTION_CONTINUE_EXECUTION)
{
}
}


 

Comments (7)

  1. Len Holgate says:

    Steve,

    If someone were writing a debugging tool and wanted to provide users of the tool with functionality similar to the thread naming shown above (i.e. provide a way for their source code to communicate with the debug tool when it is present) what would be the best way to select a value for the exception code? I’m currently assuming that there isn’t really a great deal to do except pick a value that an application programmer who decided to define their own exception code (and I expect they’re few and far between) is unlikely to pick…

  2. SteveJS says:

    Len,

    Yes, basically a random exception code is what you want. If you do have a collision with one picked by an application programmer I believe there are only two concerns:

    1. If the app programmer uses a Vectored Exception handler that tries to handle that exception code. Then use of your diagnostic function will change the app behavior. However, installing a vectored exception handler is not typical and anyone who does had better make sure they know what they are doing. They should take into account diagnostic functions compiled into the code.

    2. Your debugging tool could get confused by the applications use of the exception code.

    Basically the fact that no one will pick the same random exception code is probably good enough for most purposes.

    However, strictly speaking the exception code is only used to give you the opportunity to look in the target’s address space. You should fail gracefully when the data you want is not there. Since your debugger is looking at a buggy process there is always the possiblity that a errant thread trashed the memory you need.

  3. That’s a fair question. Part of the answer is we don’t believe people could use it properly.  The…

  4. Andy-Pennell says:

    Hey Steve, you should update this with the Win64-compatible version, which I recall has some weird packing for back-compatibility.

  5. Articles and Blog Posts Naming threads in Win32 And .NET (Steve Steiner) Reference and Sites Debugging

Skip to main content