답변

9

C# 3.0 in a Nutshell에 따르면,이는/다시 시작을 일시 중단 호출 괜찮 몇 가지 상황 중 하나입니다 다음 MDBG 코드베이스는 당신에게 시작을 줄 수 있습니다.

+0

그것이 내가 한 일입니다. – bh213

+0

힘든 교착 상태가 발생하지 않도록주의하십시오. 스레드가 필요한 잠금 장치를 보유하고있는 동안 스레드를 일시 중단하면 교착 상태가 발생합니다. 가장 일반적인 원인은 스레드가 스트림을 공유하는 것입니다 (예 : 콘솔이나 유사한 장치에 쓰기). –

2

목표 스레드의 협조없이이 작업을 수행하려는 경우 (예 : 스택 추적을 수행하는 동안 세마포어 또는 다른 방법으로 차단하는 메서드를 호출하는 등의 방법으로) 작업을 수행해야합니다. 사용되지 않는 API

가능한 대안은 .NET 디버거에서 사용하는 COM-based ICorDebug 인터페이스를 사용하는 것입니다.

+1

아니, COM이 옵션을 선택하지 않습니다. 일시 중지/이력서는 .NET의 COM 항목보다 더 깔끔한 느낌을줍니다. – bh213

14

이것은 오래된 스레드이지만 제안 된 솔루션에 대해 경고하고 싶습니다. Suspend 및 Resume 솔루션이 작동하지 않습니다. - 코드 중단시에 Suspend/StackTrace/Resume을 시도하는 데 교착 상태가 발생했습니다.

문제는 StackTrace 생성자가 RuntimeMethodHandle -> MethodBase 변환을 수행하고 이로 인해 잠금을 취하는 내부 MethodInfoCache가 변경된다는 것입니다. 교착 상태는 내가 조사한 실이 반영을하고 있었고 그 자물쇠를 잡고 있었기 때문에 발생했다.

StackTrace 생성자 내에서 일시 중단/다시 시작 작업이 수행되지 않는 것은 불편합니다.이 문제는 쉽게 회피 될 수 있습니다.

+0

완전히 사실입니다. 교착 상태가 발생했습니다. 그래도 해결 방법이있는 것 같지만 (내 대답 참조). –

19

여기에 지금까지 나를 위해 일한 무슨이다 :

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; 
} 

이 교착되면 교착 상태가 자동으로 해제하고 널 추적을 다시 얻을. (그런 다음 다시 호출 할 수 있습니다.)

몇 일간의 테스트 후 필자는 Core i7 시스템에서 교착 상태를 만들 수있었습니다. 하지만 교착 상태는 CPU가 100 %로 실행될 때 단일 코어 VM에서 일반적으로 발생합니다.

+0

두 번째'ManualResetEvent'를 사용하여 targetThread를 피할 수 있습니다.이력서는() 실행하고 예외를 throw되는 * 때마다 * ... 경우 { 시도 {targetThread.Resume() (noDeadLockSafeGuard.WaitOne (200)!); } 캐치 {} } –

+3

가 여전히 교착 상태에 대한 작은 위험이 남아 런타임은 "ready.Wait()"와 "targetThread.Suspend()"사이의 주요 스레드를 일시 중단하기로 결정하면, 당신은 여전히있을 수 있습니다 폴백 이후 교착 상태 - 스레드가 이미 종료되었습니다. IMO는 메인 스레드가 안전하게 함수를 빠져 나왔다는 시그널이있을 때만 남겨진 unlock-thread에 루프가 있어야합니다. – Andreas

+3

것은 Thread.suspend()와 경고를 오류로 사용하는 사람의 #pragma는'비활성화 0618'' 방법 전에 및 경고'' 를 사용해야합니다 그래서 Thread.resume가()는 프레임 워크에서 사용되지 않는 것으로 표시됩니다 이 코드를 컴파일하려면'#pragma warning restore 0618'' 이 필요합니다. –

10

내 의견에서 언급했듯이 제안 된 솔루션은 여전히 ​​교착 상태에 대한 가능성이 매우 낮습니다. 아래 내 버전을 찾으십시오.

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는"정말 필요하지 않습니다,하지만 왜이 민감한 경우 어떤 위험을 감수? 이 과거에 지원되는 동작처럼

+0

NB : ManualResetEventSlim은 IDisposable입니다. –

+0

@MarkSowul : using 문이 추가되었습니다. . 힌트를 가져 주셔서 감사합니다. – Andreas

+0

이 접근 방식은 교착 상태 증명이라고 말할 수 있습니까? 편집 : 당신이 코멘트를 언급했지만 OP에서 제공 한 위의 솔루션에 대한 의견을 언급했다면 확실하지 않았습니다. – Hatchling

관련 문제