有没有办法在c#中获取所有线程的堆栈跟踪,比如java.lang.Thread.getAllStackTraces()?
在java中,可以获得所有正在运行的线程的堆栈跟踪的快照。 这是通过java.lang.Thread.getAllStackTraces()
(它返回Map
)。
如何用.net做到这一点?
所以我实际上只是想弄清楚如何做到这一点 – 还没有在生产中广泛使用这个解决方案,但是还有一个名为ClrMd的相对较新的库。
使用它,我能够附加到我自己的进程并获得所有活动线程的堆栈跟踪。 在重新启动我们的应用程序之前检测到死锁时使用此方法,如下所示:
var result = new Dictionary(); var pid = Process.GetCurrentProcess().Id; using (var dataTarget = DataTarget.AttachToProcess(pid, 5000, AttachFlag.Passive)) { string dacLocation = dataTarget.ClrVersions[0].TryGetDacLocation(); var runtime = dataTarget.CreateRuntime(dacLocation); foreach (var t in runtime.Threads) { result.Add( t.ManagedThreadId, t.StackTrace.Select(f => { if (f.Method != null) { return f.Method.Type.Name + "." + f.Method.Name; } return null; }).ToArray() ); } } var json = JsonConvert.SerializeObject(result); zip.AddEntry("_threads.json", json);
使用相同的过程来AttachFlag.Passive
这一点非常重要的是AttachFlag.Passive
如果您只是执行DataTarget.AttachToProcess(pid, 5000)
,它将执行“入侵”附加,尝试暂停该过程。 当您尝试连接到您自己的进程时,这会引发exception,我假设是因为您在尝试从应用程序或类似的东西附加时无法暂停应用程序。
无论如何,是的,非常酷的东西。
如果任何人有任何理由为什么这是超级天真或任何事情,pleeeeease指出他们。 还没有在生产中使用它(只是推出了第一个实例),所以希望它有效。
如果您只想将其用于调试目的,WinDbg的SOS扩展可以为您提供此信息。
要运行的命令是“* ~e!clrstack”。
在正在运行的C#程序中,没有公开的方法来枚举托管线程或通过ID查找它们。 即使你可以,在不同的线程上获得堆栈跟踪也可能需要暂停,这有一些副作用的风险(请参阅为什么这已经过时 )。
另一种方法是在知道线程时登记线程,并在闲暇时扫描它们。 这可能只有在您显式创建线程对象而不是使用线程池时才有可能。
也就是说,我也很难看出这种方法的用途。 如果是用于调试,则可以在内存或小型转储中执行更强大的技术。 如果是用于日志记录,那么让日志记录调用贡献自己的堆栈可能是有意义的。
正如Mason of Words所暗示的那样,这在托管代码本身中看起来并不可行。 你能说清楚为什么需要这个:可能有更好的解决方案吗?
例如,如果在Visual Studio中附加到进程并按“暂停”,则“Threads”窗口将列出所有托管线程,“Stacktrace”窗口可以显示每个线程的当前堆栈跟踪。 这样就够了吗?
有一个StackTrace类
var trace = new System.Diagnostics.StackTrace(exception);
http://msdn.microsoft.com/en-us/library/system.diagnostics.stacktrace.aspx
你可以在System.Diagnostics.Process.GetCurrentProcess()上循环。线程和每个Thread创建一个带有.ctor的StackTrace对象,它以一个Thread作为它的参数。