Есть ли способ получить stacktraces для всех потоков в С#, например java.lang.Thread.getAllStackTraces()?
В Java можно получить снимок трассировки стека всех запущенных потоков.
Это делается с помощью java.lang.Thread.getAllStackTraces()
(возвращает Map<Thread,StackTraceElement[]>
).
Как это можно сделать с помощью .net?
Ответы
Ответ 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" может отображать текущую трассировку стека для каждого потока. Этого хватит?
Ответ 4
Существует класс StackTrace
var trace = new System.Diagnostics.StackTrace(exception);
http://msdn.microsoft.com/en-us/library/system.diagnostics.stacktrace.aspx
Ответ 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, который принимает поток как свой параметр.