Question

Il est possible d’obtenir stacktrace en utilisant System.Diagnostics.StackTrace, mais le thread doit être suspendu. Les fonctions Suspend et Resume sont obsolètes, je suppose donc qu’il existe un meilleur moyen.

Était-ce utile?

La solution

Selon C # 3.0 en quelques mots , il s'agit d'une des rares situations où tout va bien. appeler Suspendre / Reprendre.

Autres conseils

Voici ce qui a fonctionné pour moi jusqu'à présent:

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

S'il se bloque, le blocage est automatiquement libéré et vous récupérez une trace nulle. (Vous pouvez ensuite l'appeler à nouveau.)

Je dois ajouter qu'après quelques jours de test, je n'ai été capable qu'une seule fois de créer un blocage sur ma machine Core i7. Les blocages sont toutefois courants sur les machines virtuelles monocœur lorsque le processeur tourne à 100%.

Ceci est un ancien thread, mais je voulais juste mettre en garde sur la solution proposée: la solution Suspend and Resume ne fonctionne pas - je viens de faire l'impasse sur mon code en essayant la séquence Suspend / StackTrace / Resume.

Le problème est que le constructeur StackTrace effectue RuntimeMethodHandle - > Conversion de MethodBase et cela modifie un MethodInfoCache interne, qui est verrouillé. L’impasse s’est produite parce que le fil de discussion que j’examinais faisait également de la réflexion et maintenait ce verrou.

Il est dommage que les opérations de suspension / reprise ne soient pas effectuées dans le constructeur StackTrace. Ce problème aurait donc pu être facilement contourné.

Comme je l’ai mentionné dans mon commentaire, la solution proposée n’a toujours qu'une faible probabilité d’impasse. Veuillez trouver ma version ci-dessous.

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

Je pense que ManualResetEventSlim " fallbackThreadReady " n'est pas vraiment nécessaire, mais pourquoi ne rien risquer dans ce cas délicat?

Je pense que si vous voulez faire cela sans la coopération du thread cible (par exemple, en l'appelant une méthode qui le bloque sur un sémaphore ou quelque chose pendant que votre thread effectue le stacktrace), vous devrez utiliser le API obsolètes.

Une alternative possible est l'utilisation du ICorDebug basé sur COM. interface utilisée par les débogueurs .NET. Le code base de MDbg peut vous donner un début:

Il semble que l'opération ait été prise en charge dans le passé, mais malheureusement, Microsoft l'a rendue obsolète: https://msdn.microsoft.com/en-us/library/t2k35tat (v = vs.110) .aspx

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top