terminado - ¿Hay alguna manera de obtener los stacktraces para todos los hilos en c#, como java.lang.Thread.getAllStackTraces()?
subproceso en ejecución o terminado no se puede reiniciar (5)
En Java es posible obtener una instantánea de los stacktraces de todos los subprocesos en ejecución. Esto se hace con java.lang.Thread.getAllStackTraces()
(devuelve Map<Thread,StackTraceElement[]>
).
¿Cómo se puede hacer esto con .net?
Así que, en realidad, solo tuve que descubrir cómo hacerlo. Todavía no he usado esta solución en la producción, pero hay una biblioteca relativamente nueva llamada ClrMd.
Al usarlo, puedo adjuntarlo a mi propio proceso y obtener un seguimiento de pila para todos los subprocesos en vivo. Usando esto cuando se detecta un interbloqueo antes de reiniciar nuestra aplicación de esta manera:
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);
Lo realmente importante para que funcione a partir del mismo proceso es AttachFlag.Passive
Si solo haces DataTarget.AttachToProcess(pid, 5000)
, hará un adjunto "invasivo" que intenta pausar el proceso. Esto produce una excepción cuando intenta adjuntar a su propio proceso, supongo que no puede pausar su aplicación al intentar adjuntar desde su aplicación o algo así.
De todos modos, sí, cosas muy interesantes.
Si alguien tiene alguna razón por la que esto es super ingenuo o algo parecido, por favor, señálelos. Todavía no lo he usado mucho en la producción (solo ponga la primera instancia) así que espero que funcione.
Como sugiere Mason of Words, esto no parece posible desde el propio código administrado. ¿Podría aclarar por qué necesita esto: podría haber una mejor solución?
Por ejemplo, si se adjunta al proceso en Visual Studio y presiona "pausa", la ventana "Subprocesos" mostrará una lista de todos los subprocesos administrados, y la ventana "Stacktrace" puede mostrar el seguimiento actual de la pila para cada subproceso. ¿Sería eso suficiente?
Hay una clase StackTrace
var trace = new System.Diagnostics.StackTrace(exception);
http://msdn.microsoft.com/en-us/library/system.diagnostics.stacktrace.aspx
Puede hacer un bucle en System.Diagnostics.Process.GetCurrentProcess (). Los subprocesos y para cada Thread crean un objeto StackTrace con el .ctor que toma un Thread como parámetro.
Si desea esto solo para fines de depuración, las extensiones SOS a WinDbg pueden proporcionarle esta información.
El comando para ejecutar es "* ~ e! Clrstack".
Dentro de un programa C # en ejecución, no hay una forma pública de enumerar los hilos administrados o buscarlos por ID. Incluso si pudiera, obtener un seguimiento de pila en un subproceso diferente probablemente requiera que se suspenda, lo que conlleva algunos riesgos de efectos secundarios (vea por qué esto está obsoleto ).
La otra alternativa es enlistar los hilos como se conocen y escanearlos a su gusto. Probablemente esto solo sea posible si está creando explícitamente objetos de hilo en lugar de usar el grupo de hilos.
Dicho esto, también es difícil para mí ver a qué propósito serviría este enfoque. Si es para la depuración, hay técnicas mucho más poderosas que se pueden hacer en la memoria o en mini-volcados. Si es para el registro, entonces podría tener sentido que las llamadas de registro contribuyan a sus propias pilas.