2010-01-13 8 views

risposta

20

Quindi, in realtà, ho dovuto solo capire come farlo: non ho ancora utilizzato questa soluzione in modo estensivo nella produzione, ma esiste una libreria relativamente nuova chiamata ClrMd.

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

Con esso, sono in grado di connettersi al mio processo e ottenere una traccia dello stack per tutti i thread dal vivo.L'utilizzo di questo quando viene rilevata una situazione di stallo prima di riavviare la nostra applicazione in questo modo:

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

La cosa veramente importante per ottenere che lavorare dallo stesso processo è AttachFlag.Passive

Se lo farete DataTarget.AttachToProcess(pid, 5000), lo farà un attaccamento "invasivo" che tenta di mettere in pausa il processo. Ciò genera un'eccezione quando si tenta di collegarsi al proprio processo, presumo poiché non è possibile sospendere l'applicazione durante il tentativo di allegare dall'applicazione o qualcosa del genere.

In ogni caso, sì, roba davvero interessante.

Se qualcuno ha dei motivi per cui questo è super ingenuo o altro, per favore segnalalo. Non l'ho ancora usato molto in produzione (basta mettere la prima istanza) così sperando che funzioni.

+0

sono appena tornati alcuni dump di debug da una posizione client e questo ha funzionato per noi. molto carino. –

+0

Grande codice, grazie! Potrei suggerire di aggiungere la firma del metodo come con f.Method.GetFullSignature(). Potrebbe essere utile in caso di sovrascritture – Andrey

+0

Solo un aggiornamento: ho ottenuto risultati da questo numero piuttosto elevato di installazioni client e ha sempre funzionato ed è stato di aiuto utile. –

-5

È possibile effettuare il ciclo su System.Diagnostics.Process.GetCurrentProcess(). Fili e per ogni thread creare un oggetto StackTrace con l'.ctor che prende una discussione come parametro.

+4

Come per la risposta di @MarcosMeli, questo non è corretto. Come afferma @Hans Loken, il metodo GetCurrentProcess() restituisce un oggetto ProcessThreadCollection che contiene oggetti ProcessThread e non oggetti Thread. Per quanto posso dire, non è possibile ottenere una traccia dello stack da un ProcessThread in quanto rappresenta il thread nativo di Windows. –

-4

Provate questo

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

In res u ottenere il dizionario con la mappatura u want :)

+11

L'esecuzione di questo codice genera per me InvalidCastException. Process.Threads restituisce un oggetto ProcessThreadCollection che contiene oggetti ProcessThread e oggetti Thread. Inoltre, non è possibile convertire da ProcessThread a Thread poiché ProcessThread rappresenta thread OS mentre Thread è .net threads. –

4

Se si desidera che questo per il debug da solo, le estensioni SOS per WinDbg può dare queste informazioni .

Il comando da eseguire è "* ~ e! Clrstack".

All'interno di un programma C# in esecuzione, non esiste un modo pubblico per enumerare i thread gestiti o cercarli per ID. Anche se fosse possibile, ottenere una traccia di stack su un thread diverso richiederebbe probabilmente di sospenderlo, con alcuni rischi di effetti collaterali (vedere perché this is obsolete).

L'altra alternativa è quella di arruolare i thread come sono noti e scansionarli a vostro piacimento. Questo è probabilmente possibile solo se stai creando oggetti thread in modo esplicito anziché utilizzare il pool di thread.

Detto questo, è anche difficile per me vedere quale scopo servirebbe questo approccio. Se è per il debug, ci sono tecniche molto più potenti che possono essere fatte in memoria o in mini-dump. Se è per la registrazione, allora potrebbe essere logico che le chiamate di registrazione contribuiscano con i propri stack.

-1

Come suggerisce Mason of Words, questo non sembra possibile all'interno del codice gestito stesso. Potrebbe chiarire perché ne hai bisogno: potrebbe esserci una soluzione migliore?

Ad esempio, se si allega al processo in Visual Studio e si preme "pause", la finestra "Thread" elencherà tutti i thread gestiti e la finestra "Stacktrace" può mostrare la traccia di stack corrente per ogni thread. Sarebbe sufficiente?

Problemi correlati