В Java можно получить снимок трассировки стека всех запущенных потоков.
Это делается с помощью java.lang.Thread.getAllStackTraces()
(возвращает Map<Thread,StackTraceElement[]>
).
Как это можно сделать с помощью .net?
В Java можно получить снимок трассировки стека всех запущенных потоков.
Это делается с помощью java.lang.Thread.getAllStackTraces()
(возвращает Map<Thread,StackTraceElement[]>
).
Как это можно сделать с помощью .net?
Поэтому мне просто нужно было выяснить, как это сделать - я еще не широко использовал это решение в производстве, но есть относительно новая библиотека под названием ClrMd.
Используя его, я могу присоединиться к своему собственному процессу и получить трассировку стека для всех активных потоков. Используя это, когда обнаруживается тупик перед перезапуском нашего приложения, вот так:
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)
, он сделает "инвазивное" присоединение, которое попытается приостановить процесс. Это вызывает исключение, когда вы пытаетесь присоединиться к своему собственному процессу, я полагаю, потому что вы не можете приостановить приложение, пытаясь подключиться из приложения или что-то в этом роде.
Если вы хотите использовать это только для целей отладки, расширения SOS для WinDbg могут предоставить вам эту информацию.
Команда для запуска "* ~ e! Clrstack".
Внутри работающей программы на С# нет открытого способа перечислять управляемые потоки или искать их по ID. Даже если бы вы могли, получение трассировки стека в другом потоке, вероятно, потребовало бы его приостановки, что сопряжено с некоторыми побочными эффектами (посмотрите, почему это устарело).
Другая альтернатива - заручиться тем, как они известны, и сканировать их на досуге. Вероятно, это возможно только в том случае, если вы явно создаете объекты потоков, а не используете пул потоков.
Тем не менее, мне также трудно понять, для чего предназначен этот подход. Если это для отладки, есть гораздо более мощные методы, которые могут быть выполнены в памяти или на мини-дампах. Если это для ведения журнала, то, возможно, имеет смысл сделать так, чтобы входящие звонки вносили свой вклад.
Как говорит Mason of Words, это не представляется возможным изнутри самого управляемого кода. Не могли бы вы объяснить, зачем вам это нужно: может быть лучшее решение?
Например, если вы присоединяетесь к процессу в Visual Studio и нажимаете "pause", окно "Threads" отображает все управляемые потоки, а окно "Stacktrace" может отображать текущую трассировку стека для каждого потока. Этого хватит?
Существует класс StackTrace
var trace = new System.Diagnostics.StackTrace(exception);
http://msdn.microsoft.com/en-us/library/system.diagnostics.stacktrace.aspx
Попробуйте этот
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:)
Вы можете зацикливаться на System.Diagnostics.Process.GetCurrentProcess(). Threads и для каждого потока создают объект StackTrace с .ctor, который принимает поток как свой параметр.