有没有办法在c#中获取所有线程的堆栈跟踪,比如java.lang.Thread.getAllStackTraces()?

Dan*_*rry 26 .net c# multithreading

在java中,可以获得所有正在运行的线程的堆栈跟踪的快照.这是通过java.lang.Thread.getAllStackTraces()(它返回Map<Thread,StackTraceElement[]>)完成的.

如何用.net做到这一点?

Jos*_*sen 26

所以我实际上只是想弄清楚如何做到这一点 - 还没有在生产中广泛使用这个解决方案,但是还有一个名为ClrMd的相对较新的库.

http://blogs.msdn.com/b/dougste/archive/2013/05/04/clrmd-net-crash-dump-and-live-process-inspection.aspx

使用它,我能够附加到我自己的进程并获得所有活动线程的堆栈跟踪.在重新启动我们的应用程序之前检测到死锁时使用此方法,如下所示:

var result = new Dictionary<int, string[]>();

var pid = Process.GetCurrentProcess().Id;

using (var dataTarget = DataTarget.AttachToProcess(pid, 5000, AttachFlag.Passive))
{
    ClrInfo runtimeInfo = dataTarget.ClrVersions[0];
    var runtime = runtimeInfo.CreateRuntime();

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

让它在同一个过程中工作非常重要的是 AttachFlag.Passive

如果你这样做DataTarget.AttachToProcess(pid, 5000),它会做一个"侵入性"附着,试图暂停这个过程.当您尝试连接到自己的进程时会抛出异常,我假设是因为您在尝试从应用程序或类似的东西附加时无法暂停应用程序.

无论如何,是的,非常酷的东西.

如果任何人有任何理由为什么这是超级天真或任何东西,pleeeeease指出他们.还没有在生产中使用它(只是推出了第一个实例),所以希望它有效.


小智 6

如果您只想将其用于调试目的,WinDbg的SOS扩展可以为您提供此信息.

要运行的命令是"*~e!clrstack".

在正在运行的C#程序中,没有公开的方法来枚举托管线程或通过ID查找它们.即使你可以,在不同的线程上获得堆栈跟踪也可能需要暂停,这有一些副作用的风险(请参阅为什么这已经过时).

另一种方法是在知道线程时登记线程,并在闲暇时扫描它们.这可能只有在您显式创建线程对象而不是使用线程池时才有可能.

也就是说,我也很难看出这种方法的用途.如果是用于调试,则可以在内存或小型转储中执行更强大的技术.如果是用于日志记录,那么让日志记录调用贡献自己的堆栈可能是有意义的.