views:

222

answers:

2

Sometimes I find myself stepping through an application in Debug mode, until I hit 'step' on some particular line and it takes way too much time doing something, eating up 100% CPU. At this point, I hit the 'Break' button and try to find what's running that's taking so long.

The problem is, this app has a hefty amount of threads running, and at the time I hit 'Break', the execution point goes to the GUI thread that's probably just doing a 'Wait'. I then have to hunt through the existing threads (I counted them - this time they're 37!) trying to find the one I was executing on. I'd have to look at the stack of every one of them until I find the one I was looking for.

The thread I'm running on is an async invoke, so it runs on a thread pool thread. I'd like to give this thread a descriptive name and reset its name at the end of the operation.

The problem is, property Thread.Name can only be set once, afterwards it gives an InvalidOperationException.

Any suggestions?

Oh yeah, I'm running VS2005/.NET 2.0 but I'm also curious if newer versions have better ways to handle this.

A: 

Sure, I could take a look at the current thread ID every now and then (like before stepping every line), but:

  1. Mmmkay, that's not going to happen. Who'd ever do that?
  2. I have enough debug info on my mind already (plus the memory of a gold fish) so I'd probably lose track of the ID anyway.

EDIT Writing this got me thinking - what if I would put a trace point at the beginning of my delegate, that would print the current thread ID (as trace points do by default, IIRC)? In this case, I'd just have to find that particular message in the output pane.

This could actually work :)

Cristi Diaconescu
+1  A: 

Define your own threadstatic property

public class ThreadMarker:IDisposable
{
  [ThreadStatic]
  private static string __Name;

  static Dictionary<int,string> ThreadNames=new Dictionary<int,string>();

  public static Name{get{return __Name;}}

  public ThreadMarker(string name)
  {
    lock(ThreadNames){
      ThreadNames[Thread.CurrentThread.ManagedThreadId]=name;
    }
    __Name=name; 
  }

  public void Dispose()
  {
    ThreadNames.Remove(Thread.CurrentThread.ManagedThreadId);
    __Name="Unowned";
  } 
}

You can even write your own wrapper that automagically wraps your action / delegate / async callback in this using statement.

class NamedHandler<TArg>{
  public readonly Action<TArg> Handler;

  NamedHandler(string name,Action<TArg> handler){

    Handler=arg=>{
      using(new ThreadMarker(name)){
        handler(arg);
      }
    }     
  }
}

// usage
void doStuff(string arg){
  Log("Stuf done in thread {0} ",ThreadMarker.Name);
}    

ThreadPool.QueueUserWorkItem(new NamedHandler<string>("my Thread",arg=>DoStuff(arg)).Handler); 

Then when you stop the debugger, have a look at the contents of the variable ThreadMarker.ThreadNames and you will see which managed threads are stuck in your named handlers.

Florian Doyon
How will this help with identifying the thread within the debugger? Will it actually pick up this property instead? The internal field used for name is "m_Name" not "__Name" and it's not thread static.
Sam
I added some code for your problem.You will not be able to rename a thread once it's running. What you can do though is use a threadstatic marker field that you can check when you freeze your app to see which thread is running which of your handlers.
Florian Doyon