Вопрос

Можно получить stacktrace с помощью System.Диагностика.StackTrace, но поток должен быть приостановлен.Функции приостановки и возобновления устарели, поэтому я ожидаю, что существует лучший способ.

Это было полезно?

Решение

Согласно C # 3.0 в двух словах , это одна из немногих ситуаций, когда все в порядке позвонить Suspend / Resume.

Другие советы

Вот что сработало для меня до сих пор:

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. В то же время взаимоблокировки характерны для одноядерной виртуальной машины, когда загрузка процессора составляет 100%.

Это старый поток, но он просто хотел предупредить о предлагаемом решении: решение Suspend and Resume не работает - я только что столкнулся с тупиковой ситуацией в своем коде, пытаясь выполнить последовательность Suspend / StackTrace / Resume.

Проблема в том, что конструктор StackTrace выполняет RuntimeMethodHandle - > Преобразования MethodBase, и это меняет внутреннюю MethodInfoCache, который принимает блокировку. Тупик возник из-за того, что нить, которую я проверял, также выполняла отражение и удерживала эту блокировку.

Жаль, что приостановка / возобновление не выполняется внутри конструктора StackTrace - тогда эту проблему можно было легко обойти.

Как уже упоминалось в моем комментарии, предлагаемое решение все еще имеет небольшую вероятность тупика. Пожалуйста, найдите мою версию ниже.

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 " на самом деле не обязательно, но зачем рисковать чем-то в этом деликатном деле?

Я думаю, что если вы хотите сделать это без сотрудничества с целевым потоком (например, заставив его вызывать метод, который блокирует его в семафоре или что-то в этом роде, пока ваш поток выполняет stacktrace), вам нужно будет использовать устаревшие API.

Возможной альтернативой является использование ICorDebug на базе COM интерфейс, который используют .СЕТЕВЫЕ отладчики.Кодовая база MDbg может дать вам начало:

Похоже, что в прошлом это была поддерживаемая операция, но, к сожалению, Microsoft сделала это устаревшей: https://msdn.microsoft.com/en-us/library/t2k35tat (v = vs.110) .aspx

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top