Я не нашел способа сброса стека для всех потоков в .NET. Ни сигнал, который нужно отправить процессу, ни программный доступ ко всем потокам. Я могу получить доступ к текущему потоку через Thread.CurrentThread.
Любые трюки?
Я не нашел способа сброса стека для всех потоков в .NET. Ни сигнал, который нужно отправить процессу, ни программный доступ ко всем потокам. Я могу получить доступ к текущему потоку через Thread.CurrentThread.
Любые трюки?
Если вы пытаетесь получить дамп стека, пока процесс уже запущен (a la jstack), существует два метода, описанных здесь:
Существует малоизвестный, но эффективный инструмент, называемый Managed Stack Explorer. Хотя он имеет базовый графический интерфейс, он может эффективно быть эквивалентом .NET jstack, если вы добавите его в путь; то это просто вопрос ввода:
mse /s /p <pid>
Я просто счел необходимым взять дамп производственного потока, и это сработало для меня. Надеюсь, что это поможет: -)
Просто, чтобы сохранить кого-нибудь еще, напишите здесь порт выше, чтобы С#:
static void WriteThreadInfo(StringBuilder sw, IEnumerable<Thread> threads)
{
foreach(Thread thread in threads)
{
if(!thread.IsAlive) continue;
sw.Append(String.Concat("THREAD NAME: ", thread.Name));
sw.Append(GetStackTrace(thread));
sw.AppendLine();
sw.AppendLine();
}
}
static String GetStackTrace(Thread t)
{
t.Suspend();
var trace1 = new StackTrace(t, true);
t.Resume();
String text1 = System.Environment.NewLine;
var builder1 = new StringBuilder(255);
for (Int32 num1 = 0; (num1 < trace1.FrameCount); num1++)
{
StackFrame frame1 = trace1.GetFrame(num1);
builder1.Append(" at ");
System.Reflection.MethodBase base1 = frame1.GetMethod();
Type type1 = base1.DeclaringType;
if (type1 != null)
{
String text2 = type1.Namespace;
if (text2 != null)
{
builder1.Append(text2);
builder1.Append(".");
}
builder1.Append(type1.Name);
builder1.Append(".");
}
builder1.Append(base1.Name);
builder1.Append("(");
System.Reflection.ParameterInfo [] infoArray1 = base1.GetParameters();
for (Int32 num2 = 0; (num2 < infoArray1.Length); num2++)
{
String text3 = "<UnknownType>";
if (infoArray1[num2].ParameterType != null)
{
text3 = infoArray1[num2].ParameterType.Name;
}
builder1.Append(String.Concat(((num2 != 0) ? ", " : ""), text3, " ", infoArray1[num2].Name));
}
builder1.Append(")");
if (frame1.GetILOffset() != -1)
{
String text4 = null;
try
{
text4 = frame1.GetFileName();
}
catch (System.Security.SecurityException)
{
}
if (text4 != null)
{
builder1.Append(String.Concat(" in ", text4, ":line ", frame1.GetFileLineNumber().ToString()));
}
}
if (num1 != (trace1.FrameCount - 1))
{
builder1.Append(text1);
}
}
return builder1.ToString();
}
Я не нашел способ получить список всех управляемых потоков в С# (только ProcessThreads), поэтому похоже, что вам нужно поддерживать список тем, заинтересованных в себе.
Также я обнаружил, что не могу вызвать новую Stacktrace (t, true) в текущем потоке, поэтому добавил паузу и резюме. Очевидно, вам нужно будет подумать, может ли это вызвать проблемы, если бы вы потокостроили ваше производственное приложение.
btw, мы поместили этот вызов в наш интерфейс wcf rest, так что это легко сделать.
Лучший инструмент, который я видел на этом этапе для создания дампов потоков для .NET CLR, - DebugDiag. Этот инструмент будет генерировать очень подробный отчет (используя анализатор Crash/Hang) активных потоков CLR вместе с рекомендациями.
Я рекомендую рассмотреть следующий .NET DebugDiag учебник, поскольку он показывает процесс анализа в действии после производственной проблемы. Шаги выполняются следующим образом:
Я написал самосвал для проекта, над которым я работал в прошлом:
void CrashHandler::WriteThreadInfo(StringWriter* sw, ArrayList* threads, String* type)
{
sw->WriteLine(type);
IEnumerator* ie = threads->GetEnumerator();
while(ie->MoveNext())
{
botNETThread* bnt = static_cast<botNETThread*>(ie->Current);
if(!bnt->IsAlive) continue;
sw->WriteLine(String::Concat(S"ORIGIN ASSEMBLY: ", bnt->Assembly->FullName));
sw->WriteLine(String::Concat(S"THREAD NAME: ", (bnt->Name && bnt->Name->Length)?bnt->Name:S"Unnamed thread"));
sw->Write(GetStackTrace(bnt->_thread));
sw->WriteLine();
sw->WriteLine();
}
}
String* CrashHandler::GetStackTrace(Thread* t)
{
System::Diagnostics::StackTrace __gc * trace1 = __gc new System::Diagnostics::StackTrace(t, true);
System::String __gc * text1 = System::Environment::NewLine;
System::Text::StringBuilder __gc * builder1 = __gc new System::Text::StringBuilder(255);
for (System::Int32 num1 = 0; (num1 < trace1->FrameCount); num1++)
{
System::Diagnostics::StackFrame __gc * frame1 = trace1->GetFrame(num1);
builder1->Append(S" at ");
System::Reflection::MethodBase __gc * base1 = frame1->GetMethod();
System::Type __gc * type1 = base1->DeclaringType;
if (type1 != 0)
{
System::String __gc * text2 = type1->Namespace;
if (text2 != 0)
{
builder1->Append(text2);
if (builder1 != 0)
{
builder1->Append(S".");
}
}
builder1->Append(type1->Name);
builder1->Append(S".");
}
builder1->Append(base1->Name);
builder1->Append(S"(");
System::Reflection::ParameterInfo __gc * infoArray1 __gc [] = base1->GetParameters();
for (System::Int32 num2 = 0; (num2 < infoArray1->Length); num2++)
{
System::String __gc * text3 = S"<UnknownType>";
if (infoArray1[num2]->ParameterType != 0)
{
text3 = infoArray1[num2]->ParameterType->Name;
}
builder1->Append(System::String::Concat(((num2 != 0) ? S", " : S""), text3, S" ", infoArray1[num2]->Name));
}
builder1->Append(S")");
if (frame1->GetILOffset() != -1)
{
System::String __gc * text4 = 0;
try
{
text4 = frame1->GetFileName();
}
catch (System::Security::SecurityException*)
{
}
if (text4 != 0)
{
builder1->Append(System::String::Concat(S" in ", text4, S":line ", frame1->GetFileLineNumber().ToString()));
}
}
if (num1 != (trace1->FrameCount - 1))
{
builder1->Append(text1);
}
}
return builder1->ToString();
}
Вы можете использовать Process.GetCurrentProcess(). Темы для получения тем
И я знаю, что я искал управляемый С++, но его достаточно легко следовать. Я беру arraylist из нитей, потому что для своей цели я катафорировал свои потоки. И да, я использовал ранее написанный код кадра кадра, поскольку я был новым для MС++ в то время:)
Весь файл здесь. Это было для Diablo II botting engine Я написал некоторое время назад.
В System.Diagnostics есть множество удобных классов, которые могут помочь вам в отладке и сборе различной информации отслеживания, т.е. StackTrace.
Существует класс winky Process, который может использоваться для получения количества исполняемых потоков, но очень мало деталей. Используйте следующий фрагмент:
Using System.Diagnostics;
var threads = Process.GetCurrentProcess().Threads;
Хорошо, посмотрев немного больше, кажется, самый простой способ захватить все текущие стеки - через мини-дамп и инструмент вроде SOS или если вы используете vista this.
Удачи.
Если вам нужно сделать это программно (возможно, вам нужны автоматические дампы во время процесса CI), вы можете использовать информацию из этого ответа для другого вопроса.
В принципе, присоединитесь к своему собственному процессу, используя CLR MD:
using Microsoft.Diagnostics.Runtime;
using (DataTarget target = DataTarget.AttachToProcess(
Process.GetCurrentProcess().Id, 5000, AttachFlag.Passive))
{
ClrRuntime runtime = target.ClrVersions.First().CreateRuntime();
foreach (ClrThread thread in runtime.Threads)
{
IList<ClrStackFrame> stackFrames = thread.StackTrace;
PrintStackTrace(stackFrames);
}
}
Здесь PrintStackTrace остается в качестве упражнения для читателя.