Es posible obtener stacktrace utilizando System.Diagnostics.StackTrace, pero el hilo debe suspenderse. Las funciones Suspender y Reanudar son obsoletas, por lo que espero que exista una mejor manera.¿Cómo obtener stacktrace de hilo no actual?
Respuesta
Según C# 3.0 in a Nutshell, esta es una de las pocas situaciones en las que es aceptable llamar suspender/reanudar.
Creo que si quieres hacer esto sin la cooperación del hilo de destino (por ejemplo, haciendo que llame a un método que lo bloquea en un semáforo o algo así mientras tu hilo hace el stacktrace) tendrás que usar las API desaprobadas.
Una posible alternativa es el uso de la interfaz COM-based ICorDebug que utilizan los depuradores .NET. El código base MDBG podría darle un comienzo:
No, COM no es una opción. Suspender/Reanudar se siente mucho más limpio que las cosas COM de .NET ... – bh213
Este es un tema viejo, pero solo quería advertir sobre la solución propuesta: la solución Suspender y Reanudar no funciona - Acabo de experimentar un punto muerto en mi código al intentar la secuencia Suspender/Pilatizar/Reanudar.
El problema es que el constructor de StackTrace realiza conversiones de RuntimeMethodHandle -> MethodBase, y esto cambia una MethodInfoCache interna, que toma un bloqueo. El punto muerto se produjo porque el hilo que estaba examinando también estaba haciendo un reflejo, y estaba sosteniendo ese bloqueo.
Es una lástima que las cosas de suspender/reanudar no se realicen dentro del constructor de StackTrace; entonces, este problema podría haberse eludido fácilmente.
Totalmente cierto: me he encontrado con deadlocks haciendo esto. Sin embargo, parece haber una solución alternativa (ver mi respuesta). –
Esto es lo que ha funcionado para mí hasta ahora:
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;
}
Si se bloquea al principio, el punto muerto se libera automáticamente y volver un rastro nulo. (Puede llamarlo de nuevo.)
Debo añadir que después de unos días de prueba, solo una vez he podido crear un interbloqueo en mi máquina Core i7. Los bloqueos son comunes, sin embargo, en la VM de un solo núcleo cuando la CPU funciona al 100%.
Es posible que desee utilizar un segundo 'ManualResetEvent' para evitar targetThread.Reanudar() se ejecuta y lanza una excepción * cada vez * ... if (! NoDeadLockSafeGuard.WaitOne (200)) { try {targetThread.Resume(); } catch {} } –
Todavía hay un pequeño riesgo de que quede un punto muerto: si el tiempo de ejecución decide suspender el hilo principal entre "ready.Wait()" y "targetThread.Suspend()", es posible que todavía tenga un punto muerto desde que el hilo de reserva ya salió. IMO necesita tener un bucle en el hilo de desbloqueo que queda solo cuando el hilo principal indica que salió de la función de forma segura. – Andreas
Thread.suspend() y Thread.Resume() están marcadas como obsoletas en el marco, por lo que cualquier persona que utilice advertencias como errores tendrá que utilizar '' #pragma warning desactivar 0618'' antes de que el método y ' '#pragma warning restore 0618'' después para obtener este código para compilar. –
Como mencioné en mi comentario, la solución propuesta todavía tiene una pequeña probabilidad de un punto muerto. Por favor encuentra mi versión a continuación.
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();
}
}
}
creo, la ManualResetEventSlim "fallbackThreadReady" no es realmente necesario, pero ¿por qué arriesgar nada en este caso delicada?
NB: ManualResetEventSlim es IDisposable –
@MarkSowul: se agregó una sentencia using . gracias por la pista. – Andreas
¿Diría que este enfoque es una prueba de estancamiento? Editar: mencionó un comentario, pero no estaba seguro de si se refería a un comentario sobre la solución anterior proporcionada por el OP. – Hatchling
Parece que este fue una operación apoyado en el pasado, pero, por desgracia, Microsoft hizo esta obsoleta: https://msdn.microsoft.com/en-us/library/t2k35tat(v=vs.110).aspx
- 1. Cómo obtener Clojure Stacktrace
- 2. ¿Cómo obtener stacktrace completo en SBT 0.10.0?
- 3. Obtener stacktrace del proceso de python atascado
- 4. ¿Obtener una stacktrace más larga de FastMM?
- 5. ¿Cómo puedo suspender otro hilo (no el actual)?
- 6. Método del hilo actual java
- 7. Cómo obtener valor de los parámetros en StackTrace
- 8. org.hibernate.HibernateException: No se encontró Sesión de hilo actual
- 9. Clojure tools.logging no logging stacktrace
- 10. ¿Número de hilo actual de Jmeter?
- 11. Obtención de Stacktrace
- 12. ¿Cómo obtener el contexto actual?
- 13. Compruebe si el hilo actual es el hilo principal
- 14. Cómo obtener la hora actual
- 15. ¿Cómo obtener el lienzo actual?
- 16. ¿Cómo obtener el estado de un hilo?
- 17. C#: cómo obtener la longitud del hilo en el hilo []
- 18. ¿Cómo obtener el directorio actual?
- 19. Obtener un rastreo de otro hilo
- 20. ¿Cómo enviar una stacktrace a log4j?
- 21. ¿Cómo verificar el estado del apartamento del hilo actual?
- 22. NDK/JNI: identificando el hilo actual
- 23. ¿Cómo obtener la orientación actual de iPhones?
- 24. de cómo obtener la URL actual
- 25. ¿Cómo encontrar el nombre de la clase llamada de método de inicio de un hilo usando StackTrace
- 26. Obtener dominio actual
- 27. ¿Cómo obtener el ID de proceso actual?
- 28. ¿Cómo obtener el sello de hora actual?
- 29. ¿Cómo obtener el área de ejecución actual?
- 30. ¿Cómo obtener el número de línea actual?
Eso es lo que terminé haciendo. – bh213
Tenga cuidado de no introducir puntos muertos difíciles. Si suspendes un hilo mientras está sosteniendo un bloqueo que necesitas, tendrás un punto muerto. La causa más común probablemente sería si los subprocesos comparten una secuencia (por ejemplo, escribir en la consola o similar). –