Pergunta

É possível obter stacktrace usando System.Diagnostics.StackTrace, mas thread tem de ser suspenso. Suspender e função Resume são obsoletos, por isso espero que melhor maneira existe.

Foi útil?

Solução

De acordo com a C # 3.0 in a Nutshell , esta é uma das poucas situações em que é aprovado para chamar Suspender / Reactivar.

Outras dicas

Aqui está o que funcionou para mim até agora:

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

Se impasses, o impasse é automaticamente liberado e você recebe de volta um traço nulo. (Você pode, em seguida, chamá-lo novamente.)

Gostaria de acrescentar que depois de alguns dias de testes, eu tenho apenas uma vez sido capaz de criar um impasse na minha máquina Core i7. Impasses são comuns, embora, em single-core VM quando a CPU é executado em 100%.

Esta é uma discussão antiga, mas só queria avisar sobre a solução proposta:. O Suspender e solução Resume não funciona - Eu só experimentou um impasse no meu código tentar a seqüência Suspender / StackTrace / Resume

O problema é que StackTrace construtor faz RuntimeMethodHandle -> conversões MethodBase, e isso muda um MethodInfoCache interna, que leva um bloqueio. O impasse ocorreu porque o thread eu estava examinando também estava fazendo reflexão, e estava segurando aquela fechadura.

É uma pena que a suspensão / stuff currículo não é feito dentro do construtor StackTrace -então este problema poderia ter sido facilmente contornada.

Como mencionado no meu comentário, a solução proposta ainda tem uma pequena probabilidade de um impasse. Por favor, encontrar a minha versão abaixo.

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

Eu acho que, a ManualResetEventSlim "fallbackThreadReady" não é realmente necessário, mas por que arriscar qualquer coisa neste caso delicado?

Eu acho que se você quiser fazer isso sem a cooperação do segmento-alvo (como por tê-lo chamar um método que bloqueia-lo em um semáforo ou algo enquanto seu segmento faz o stacktrace) você vai precisar usar o APIs obsoleto.

Uma alternativa possível é o uso do ICorDebug baseada em COM Interface que os depuradores .NET usar. A base de código MDBG pode dar-lhe um começo:

Parece que este foi uma operação apoiada no passado, mas, infelizmente, a Microsoft fez isso obsoleto: https://msdn.microsoft.com/en-us/library/t2k35tat (v = vs.110) .aspx

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top