有时我发现自己在调试模式下单步执行应用程序,直到我在某个特定行上点击'step'并且需要花费太多时间做某事,占用100%的CPU。在这一点上,我按下了“Break”按钮,试着找出运行时间这么长的东西。
问题是,这个应用程序运行了大量的线程,当我点击“Break”时,执行点转到可能只是在做“等待”的GUI线程。 然后,我必须通过现有的线程(我计算它们 - 这次是37岁!)试图找到我正在执行的线程。我必须看看每一个的堆栈,直到找到我要找的那个。
我正在运行的线程是异步调用,因此它在线程池线程上运行。 我想给这个线程一个描述性名称,并在操作结束时重置它的名字。
问题是,属性Thread.Name
只能设置一次,之后它会提供InvalidOperationException
。
有什么建议吗?
哦,是的,我正在运行VS2005 / .NET 2.0,但我也很好奇新版本是否有更好的方法来处理这个问题。
答案 0 :(得分: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";
}
}
您甚至可以编写自己的包装器,在此using语句中自动包装您的action / delegate / async回调。
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);
然后当您停止调试器时,查看变量ThreadMarker.ThreadNames的内容,您将看到哪些托管线程卡在您的命名处理程序中。