伙计,我的线程在哪里?(或:重命名.NET线程池线程 - 是否可能?)

Cri*_*scu 12 .net c# debugging multithreading

有时我发现自己在调试模式下单步执行应用程序,直到我在某个特定行上点击'step'并且需要花费太多时间做某事,占用100%的CPU.在这一点上,我按下了"Break"按钮,试着找出运行时间这么长的东西.

问题是,这个应用程序运行了大量的线程,当我点击"Break"时,执行点转到GUI线程,可能只是在做"等待".然后,我必须通过现有的线程(我计算它们 - 这次是37岁!)试图找到我正在执行的线程.我必须看看每一个的堆栈,直到找到我要找的那个.

我正在运行的线程是异步调用,因此它在线程池线程上运行.我想给这个线程一个描述性名称,并在操作结束时重置它的名字.

问题是,属性Thread.Name只能设置一次,之后它会给出一个InvalidOperationException.

有什么建议?

哦,是的,我正在运行VS2005/.NET 2.0,但我也很好奇,如果新版本有更好的方法来处理这个问题.

Flo*_*yon 4

定义自己的 threadstatic 属性

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";
  } 
}
Run Code Online (Sandbox Code Playgroud)

您甚至可以编写自己的包装器,自动将您的操作/委托/异步回调包装在此 using 语句中。

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); 
Run Code Online (Sandbox Code Playgroud)

然后,当您停止调试器时,查看变量 ThreadMarker.ThreadNames 的内容,您将看到哪些托管线程卡在您的命名处理程序中。