Подтвердить что ты не робот

Есть ли способ получить stacktraces для всех потоков в С#, например java.lang.Thread.getAllStackTraces()?

В Java можно получить снимок трассировки стека всех запущенных потоков. Это делается с помощью java.lang.Thread.getAllStackTraces() (возвращает Map<Thread,StackTraceElement[]>).

Как это можно сделать с помощью .net?

4b9b3361

Ответ 1

Поэтому мне просто нужно было выяснить, как это сделать - я еще не широко использовал это решение в производстве, но есть относительно новая библиотека под названием 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);

Очень важно, чтобы это работало из одного и того же процесса - AttachFlag.Passive

Если вы просто сделаете DataTarget.AttachToProcess(pid, 5000), он сделает "инвазивное" присоединение, которое попытается приостановить процесс. Это вызывает исключение, когда вы пытаетесь присоединиться к своему собственному процессу, я полагаю, потому что вы не можете приостановить приложение, пытаясь подключиться из приложения или что-то в этом роде.

Ответ 2

Если вы хотите использовать это только для целей отладки, расширения SOS для WinDbg могут предоставить вам эту информацию.

Команда для запуска "* ~ e! Clrstack".

Внутри работающей программы на С# нет открытого способа перечислять управляемые потоки или искать их по ID. Даже если бы вы могли, получение трассировки стека в другом потоке, вероятно, потребовало бы его приостановки, что сопряжено с некоторыми побочными эффектами (посмотрите, почему это устарело).

Другая альтернатива - заручиться тем, как они известны, и сканировать их на досуге. Вероятно, это возможно только в том случае, если вы явно создаете объекты потоков, а не используете пул потоков.

Тем не менее, мне также трудно понять, для чего предназначен этот подход. Если это для отладки, есть гораздо более мощные методы, которые могут быть выполнены в памяти или на мини-дампах. Если это для ведения журнала, то, возможно, имеет смысл сделать так, чтобы входящие звонки вносили свой вклад.

Ответ 3

Как говорит Mason of Words, это не представляется возможным изнутри самого управляемого кода. Не могли бы вы объяснить, зачем вам это нужно: может быть лучшее решение?

Например, если вы присоединяетесь к процессу в Visual Studio и нажимаете "pause", окно "Threads" отображает все управляемые потоки, а окно "Stacktrace" может отображать текущую трассировку стека для каждого потока. Этого хватит?

Ответ 5

Попробуйте этот

var proc = System.Diagnostics.Process.GetCurrentProcess();
var threads = proc.Threads;

var res = new Dictionary<Thread, StackTrace>();
foreach (Thread thread in threads)
{
    var stackTrace = new StackTrace(thread, true);
    res.Add(thread, stackTrace);
}

В res u получите словарь с отображением u want:)

Ответ 6

Вы можете зацикливаться на System.Diagnostics.Process.GetCurrentProcess(). Threads и для каждого потока создают объект StackTrace с .ctor, который принимает поток как свой параметр.