2010-01-13 8 views

Odpowiedz

20

Tak więc właśnie musiałem wymyślić, jak to zrobić - nie korzystałem jeszcze z tego rozwiązania w produkcji, ale jest tam stosunkowo nowa biblioteka o nazwie ClrMd.

http://blogs.msdn.com/b/dougste/archive/2013/05/04/clrmd-net-crash-dump-and-live-process-inspection.aspx

Używając go, jestem w stanie dołączyć do własnego procesu i uzyskać ślad stosu dla wszystkich wątków na żywo.Stosując ten po wykryciu zakleszczenia przed ponownym naszą aplikację tak:

var result = new Dictionary<int, string[]>(); 

var pid = Process.GetCurrentProcess().Id; 

using (var dataTarget = DataTarget.AttachToProcess(pid, 5000, AttachFlag.Passive)) 
{ 
    string dacLocation = dataTarget.ClrVersions[0].TryGetDacLocation(); 
    var runtime = dataTarget.CreateRuntime(dacLocation); 

    foreach (var t in runtime.Threads) 
    { 
     result.Add(
      t.ManagedThreadId, 
      t.StackTrace.Select(f => 
      { 
       if (f.Method != null) 
       { 
        return f.Method.Type.Name + "." + f.Method.Name; 
       } 

       return null; 
      }).ToArray() 
     ); 
    } 
} 

var json = JsonConvert.SerializeObject(result); 

zip.AddEntry("_threads.json", json); 

Naprawdę ważną rzeczą, aby ta do pracy z tego samego procesu jest AttachFlag.Passive

Jeśli po prostu zrobić DataTarget.AttachToProcess(pid, 5000), to zrobi "inwazyjny" załącznik, który próbuje wstrzymać proces. Wywołuje to wyjątek podczas próby dołączenia do własnego procesu, zakładam, że nie można wstrzymać aplikacji, próbując dołączyć z aplikacji lub coś podobnego.

W każdym razie, tak, całkiem fajne rzeczy.

Jeśli ktoś ma jakieś powody, dla których jest super naiwny, lub cokolwiek, proszę je wskazać. Nie użyłem go jeszcze w produkcji (po prostu wypuść pierwszą instancję), mając nadzieję, że to zadziała.

+0

właśnie wróciło kilka zrzutów debugowania z lokalizacji klienta i to działało dla nas. całkiem fajne. –

+0

Świetny kod, dziękuję! Mogłabym zasugerować dodanie podpisu metody jak przy f.Method.GetFullSignature(). Może to być pomocne w przypadku przesłonięć – Andrey

+0

Po prostu aktualizacja - otrzymałem wyniki z dość dużej liczby instalacji klienta i zawsze działało i było przyzwoicie pomocne. –

-5

Można pętla na System.Diagnostics.Process.GetCurrentProcess(). Nici i dla każdego wątku utworzyć obiekt StackTrace z .ctor który zabierze wątek jako jego parametr.

+4

Podobnie jak w przypadku odpowiedzi @ MarcosMeli, jest to niepoprawne. Jak stwierdza @Hans Loken, metoda GetCurrentProcess() zwraca obiekt ProcessThreadCollection zawierający obiekty ProcessThread, a nie obiekty Thread. O ile mogę powiedzieć, nie można uzyskać śledzenia stosu z ProcessThread, ponieważ reprezentuje natywny wątek systemu Windows. –

-4

Spróbuj jeden

var proc = System.Diagnostics.Process.GetCurrentProcess(); 
var threads = proc.Threads; 

var res = new Dictionary<Thread, StackTrace>(); 
foreach (Thread thread in threads) 
{ 
    var stackTrace = new StackTrace(thread, true); 
    res.Add(thread, stackTrace); 
} 

w OZE u dostać słownika z mapowaniem u chcą :)

+11

Uruchamianie tego kodu generuje dla mnie wyjątek InvalidCastException. Process.Threads zwraca ProcessThreadCollection, który zawiera obiekty ProcessThread, a nie obiekty Thread. Ponadto, nie ma możliwości konwersji z ProcessThread na wątek, ponieważ ProcessThread reprezentuje wątki systemu operacyjnego, podczas gdy wątek jest wątkiem .net. –

4

Jeśli chcesz tego samego dla celów debugowania, rozszerzenia SOS WinDbg może dać ci tę informację .

Polecenie uruchomienia to "* ~ e! Clrstack".

Wewnątrz działającego programu C# nie ma publicznego sposobu na wyliczenie zarządzanych wątków lub wyszukanie ich za pomocą identyfikatora. Nawet gdyby było to możliwe, pobranie śladu stosu na innym wątku prawdopodobnie wymagałoby zawieszenia, co wiąże się z ryzykiem wystąpienia efektów ubocznych (zobacz, dlaczego this is obsolete).

Inną alternatywą jest rejestracja wątków w znany sposób i skanowanie ich w czasie wolnym. Jest to prawdopodobnie możliwe tylko wtedy, gdy jawnie tworzysz obiekty wątku, zamiast używać puli wątków.

To powiedziawszy, również trudno jest mi zobaczyć, jaki cel miałby służyć to podejście. Jeśli służy do debugowania, istnieją o wiele potężniejsze techniki, które można wykonać w pamięci lub na mini-zrzutach. Jeśli służy do rejestrowania, może być sensowne, aby połączenia z logowaniem miały swój własny stos.

-1

Jak sugeruje Mason of Words, nie jest to możliwe z poziomu samego kodu zarządzanego. Czy możesz wyjaśnić, dlaczego tego potrzebujesz: może być lepsze rozwiązanie?

Na przykład, jeśli dołączysz do procesu w Visual Studio i naciśniesz "pauza", wtedy okno "Wątki" wyświetli listę wszystkich zarządzanych wątków, a okno "Stacktrace" może pokazać bieżący ślad stosu dla każdego wątku. Czy to wystarczy?

Powiązane problemy