현재가 아닌 스레드의 스택 추적을 얻는 방법은 무엇입니까?
-
08-07-2019 - |
문제
System.Diagnostics.StackTrace를 사용하여 스택 추적을 가져올 수 있지만 스레드를 일시 중단해야 합니다.Suspend 및 Resume 기능은 더 이상 사용되지 않으므로 더 나은 방법이 있을 것으로 기대합니다.
해결책
에 따르면 간단히 말해서 C# 3.0, 이것은 서스펜션/이력서를 호출해도 괜찮은 몇 가지 상황 중 하나입니다.
다른 팁
지금까지 저를 위해 일한 것은 다음과 같습니다.
StackTrace GetStackTrace (Thread targetThread)
{
StackTrace stackTrace = null;
var ready = new ManualResetEventSlim();
new Thread (() =>
{
// Backstop to release thread in case of deadlock:
ready.Set();
Thread.Sleep (200);
try { targetThread.Resume(); } catch { }
}).Start();
ready.Wait();
targetThread.Suspend();
try { stackTrace = new StackTrace (targetThread, true); }
catch { /* Deadlock */ }
finally
{
try { targetThread.Resume(); }
catch { stackTrace = null; /* Deadlock */ }
}
return stackTrace;
}
교착 상태가 있으면 교착 상태가 자동으로 해제되고 널 추적을 되 찾습니다. (그런 다음 다시 전화 할 수 있습니다.)
며칠 동안 테스트를 마친 후에는 코어 i7 컴퓨터에서 교착 상태를 만들 수있었습니다. 그러나 CPU가 100%로 실행될 때 단일 코어 VM에서 교착 상태가 일반적입니다.
이것은 오래된 스레드이지만 제안 된 솔루션에 대해 경고하고 싶었습니다. Sustend and Resume 솔루션은 작동하지 않습니다. 제 코드에서 시퀀스 중단/스택 트레이스/이력서를 시도하는 데 교착 상태가 발생했습니다.
문제는 stacktrace 생성기가 runtimemethodhandle-> methodbase conversions를 실행한다는 것입니다. 이는 내부 MethodinFocache를 변경하여 잠금을 취합니다. 교착 상태는 내가 검사하고있는 실이 또한 반사하고 있었고 그 자물쇠를 잡고 있었기 때문에 발생했습니다.
스택 트레이스 생성자 내부에서 일시 중단/이력서 물건이 수행되지 않는 것은 유감입니다.이 문제는 쉽게 우회 할 수있었습니다.
내 의견에서 언급했듯이 제안된 솔루션에는 교착 상태가 발생할 가능성이 여전히 적습니다.아래에서 내 버전을 찾아보세요.
private static StackTrace GetStackTrace(Thread targetThread) {
using (ManualResetEvent fallbackThreadReady = new ManualResetEvent(false), exitedSafely = new ManualResetEvent(false)) {
Thread fallbackThread = new Thread(delegate() {
fallbackThreadReady.Set();
while (!exitedSafely.WaitOne(200)) {
try {
targetThread.Resume();
} catch (Exception) {/*Whatever happens, do never stop to resume the target-thread regularly until the main-thread has exited safely.*/}
}
});
fallbackThread.Name = "GetStackFallbackThread";
try {
fallbackThread.Start();
fallbackThreadReady.WaitOne();
//From here, you have about 200ms to get the stack-trace.
targetThread.Suspend();
StackTrace trace = null;
try {
trace = new StackTrace(targetThread, true);
} catch (ThreadStateException) {
//failed to get stack trace, since the fallback-thread resumed the thread
//possible reasons:
//1.) This thread was just too slow (not very likely)
//2.) The deadlock ocurred and the fallbackThread rescued the situation.
//In both cases just return null.
}
try {
targetThread.Resume();
} catch (ThreadStateException) {/*Thread is running again already*/}
return trace;
} finally {
//Just signal the backup-thread to stop.
exitedSafely.Set();
//Join the thread to avoid disposing "exited safely" too early. And also make sure that no leftover threads are cluttering iis by accident.
fallbackThread.Join();
}
}
}
내 생각에는 ManualResetEventSlim "fallbackThreadReady"가 실제로 필요하지는 않지만 이 민감한 경우에 위험을 감수할 이유가 무엇입니까?
대상 스레드의 협력 없이이 작업을 수행하려면 (예 : 세마포어 또는 스레드가 스택 트레이스를 수행하는 동안 세마포어에서 차단하는 메소드를 호출하는 것과 같은 경우) 더 이상 사용되지 않은 API를 사용해야한다고 생각합니다.
가능한 대안은 사용입니다 com 기반 Icordebug .NET 디버거가 사용하는 인터페이스. MDBG 코드베이스는 다음을 시작할 수 있습니다.
이것은 과거에 지원되는 운영 인 것 같지만 불행히도 Microsoft는 다음과 같습니다. https://msdn.microsoft.com/en-us/library/t2k35tat(v=vs.110).aspx