Introduction
We all know that we should name our variables well, with a descriptive name. How many of you name the threads you spawn? Raise hands if you do!
Ever seen something similar to the line below? Then read on.
The thread 0x1ce4 has exited with code -2147023895 (0x800703e9).
Using the Code
Whenever you start a thread, name it. Not just the variable that you are holding the task in, but the actual thread. Make it a habit to do so whenever you program a task or thread, starting with your main-thread.
static void Main()
{
Thread.CurrentThread.Name = String.Format(
"Main UI thread for {0}",
Application.ProductName);
Task BackgroundJsonLoader = Task.Factory.StartNew(() =>
{
Thread.CurrentThread.Name =
"BackgroundJsonLoader_C71B0546796D46A894925EAF6A0CF420";
Debugger.Break();
Run your application and pause it somewhere. From the main-menu, choose the menu "debugging", then the submenu "Windows" and then the item "Threads" (Ctrl D, T). You'll now get a list of all active threads in the application, like shown below:
That's showing the managed Id, the name (if you properly named it!) and the priority. You can do the same for a BackgroundWorker
by setting the name in the DoWork
-event.
The reason for the weird number in the name is simple; I generate a Guid from the IDE and paste it there. Whenever the name comes up in a log, I can quickly search the code.
Beware async!
An await expression in an async method doesn’t block the current thread while the awaited task is running. Instead, the expression signs up the rest of the method as a continuation and returns control to the caller of the async method. The async and await keywords don't cause additional threads to be created. Async methods don't require multithreading because an async method doesn't run on its own thread. The method runs on the current synchronization context and uses time on the thread only when the method is active.
Meaning that if you call something in async
, it will be running on some unnamed synchronization thread, but not a new one.
Bonus
You can get/set the threadname using that single one-liner; so also from your base-exception class. If you have a single base-class for all your exceptions, then it would be easy to update all thrown exceptions. If you haven't, well, now you know why you should have.
No, I don't like Dutch translations of the exception-texts of the framework. They're confusing as heck. :)
Results
Going back to the original problem, the thread-Id will obviously change on every run.
The thread 0x1ce4 has exited with code -2147023895 (0x800703e9).
Using the IDE, we can check which threads are running, and their names might give a good hint on what is happening. Logging should make it possible to match up a thread-ID with a name.
I hope it saves someone some time with debugging :beer: