2009-12-16 15 views
6

Tengo una aplicación de Windows muy grande y compleja (millones + LOC) escrita en C++. Recibimos un puñado de informes cada día que la aplicación se ha bloqueado y deben cerrarse con fuerza.Detectando aplicación hang

Si bien tenemos informes extensos acerca de fallas en el lugar, me gustaría expandir esto para incluir estos escenarios de suspensión: incluso con un registro pesado implementado, no hemos podido rastrear las causas raíz de algunos de estos. Podemos ver claramente dónde se detuvo la actividad, pero no por qué se detuvo, incluso al evaluar la salida de todos los hilos.

El problema es detectar cuándo se produce un bloqueo. Hasta ahora, lo mejor que se me ocurre es un hilo de vigilancia (ya que tenemos evidencia de que los hilos de fondo continúan ejecutándose sin problemas) que periódicamente hace sonar la ventana principal con un mensaje personalizado, y confirma que se maneja en una de manera oportuna. Esto solo capturará el bloqueo de la interfaz gráfica de usuario (GUI), pero parece ser que está ocurriendo la mayoría de ellos. Si no se recibiera una respuesta dentro de un marco de tiempo configurable, capturaríamos un volcado de memoria y pila, y le daremos al usuario la opción de continuar esperando o reiniciando la aplicación.

¿Alguien sabe de una mejor manera de hacer esto que un sondeo periódico de la ventana principal de esta manera? Parece dolorosamente torpe, pero no he visto alternativas que funcionen en nuestras plataformas: Windows XP y Windows 2003 Server. Veo que Vista tiene herramientas mucho mejores para esto, pero desafortunadamente eso no nos ayudará.

Baste decir que hemos realizado diagnósticos extensos al respecto y hemos tenido un éxito limitado. Tenga en cuenta que adjuntar windbg en tiempo real no es una opción, ya que no obtenemos los informes hasta horas o días después del incidente. Podríamos recuperar un volcado de memoria y archivos de registro, pero nada más.

Cualquier sugerencia más allá de lo que estoy planeando arriba sería apreciada.

+0

Cuando se bloquea, ¿todos los hilos se bloquean? ¿La aplicación continúa generando archivos de registro? –

+0

¿Desea que la aplicación en sí detecte que se ha colgado o tiene un proceso separado para monitorear la aplicación? –

+0

La aplicación, en la mayoría de los escenarios, continúa generando el registro en otros hilos que la ventana principal. En un porcentaje muy bajo de casos, parece que todo el registro se detiene en los hilos. Queremos que la aplicación se autocontrole. –

Respuesta

2

La respuesta es simple: SendMessageTimeout!

Al usar esta API, puede enviar un mensaje a una ventana y esperar un tiempo de espera antes de continuar; si la aplicación responde antes de que se agote el tiempo de espera, todavía se está ejecutando; de lo contrario, se cuelga.

+0

Gracias, no sabía nada de esto, eso funcionará bien con lo que ya estoy planeando. –

1

Una sugerencia:

Suponiendo que el problema se debe al bloqueo, se puede volcar el mutex & estados de semáforos de un hilo de vigilancia. Con un poco de trabajo (rastreando el gráfico de llamadas), puede determinar cómo llegó a un punto muerto, qué rutas de acceso se bloquean mutuamente, etc.

+0

Gracias, es una buena sugerencia para después de que hayamos detectado el hecho de que estamos bloqueados, pero estoy buscando primero una manera confiable de hacerlo. –

3

Una opción es ejecutar su programa bajo su propio "depurador" " todo el tiempo. Algunos programas, como GetRight, hacen esto para la protección contra copia, pero también puedes hacerlo para detectar bloqueos. Básicamente, incluyes en tu programa un código para adjuntar a un proceso a través de la API de depuración y luego utilizas esa API para verificar periódicamente si hay bloqueos. Cuando el programa se inicia por primera vez, comprueba si hay un depurador adjunto y, si no, ejecuta otra copia de sí mismo y se une a él, por lo que la primera instancia no hace más que actuar como el depurador y la segunda instancia es la "real " uno.

La forma en que realmente comprueba si cuelga es otra cuestión, pero al tener acceso a la API de depuración debería haber alguna manera de comprobar razonablemente si la pila ha cambiado o no (es decir, sin cargar todos los símbolos). Aún así, es posible que solo necesite hacer esto cada pocos minutos más o menos, por lo que incluso si no es eficiente, podría estar bien.

Es una solución un tanto extrema, pero debería ser efectiva. También sería bastante fácil activar y desactivar este comportamiento, un cambio en la línea de comando o un #define si lo prefiere. Estoy seguro de que hay algún código que ya hace cosas como esta, por lo que probablemente no tengas que hacerlo desde cero.

+0

Gracias, echaré un vistazo a esto. Estoy preocupado por los gastos generales involucrados. La aplicación ya es enorme, y debido a la naturaleza compartida del entorno de servicios de terminal, hemos llegado a un punto en el que agregar cualquier memoria significativa o sobrecarga de CPU podría ser problemático. –

0

Si bien un análisis de crashdump parece proporcionar una solución para identificar el problema, en mi experiencia esto rara vez da mucho fruto ya que carece de suficiente detalle inequívoco de lo que sucedió justo antes del accidente. Incluso con la herramienta que propone, proporcionaría poco más que evidencia circunstancial de lo que sucedió. Apuesto a que la causa son datos compartidos no protegidos, por lo que un rastreo de bloqueo no lo mostrará.

La forma más productiva de encontrar esto, en mi experiencia, es destilar la lógica de la aplicación a su esencia e identificar dónde deben estar ocurriendo los conflictos. ¿Cuántos hilos hay? ¿Cuántos son GUI? ¿En cuántos puntos interactúan los hilos? Sí, esta es una buena comprobación de escritorio. Las principales interacciones sospechosas pueden identificarse en un día o dos, y luego convencer a un pequeño grupo de escépticos de que la interacción es correcta.

+0

Cierto, y ciertamente hemos intentado esto (y seguimos intentando esto), pero hasta ahora no hemos podido reproducir esto en sus formas originales o en una forma "recortada". Incluso después de identificar posibles interacciones sospechosas, aún no podemos obligar a que ocurra el escenario. No espero que el vertedero sea la bala mágica, sino más bien otro arma poderosa en el arsenal: tener un seguimiento de la pila puede proporcionar mucha información incluso sin ninguno de los otros datos que contendrá el vertedero. –

+0

No me refiero a hacer código destilable ejecutable. Quiero decir destilar el código en su núcleo funcional e interacciones, como en una hoja de papel o pizarra: 'tarea1: inicializar; lazo; wait_for_signal; perform_listbox_update; until (terminated); ' – wallyk

+0

Nos hemos acercado desde ese ángulo también. Gran parte del problema es que hay varios caminos diferentes que parecen conducir a esto, por lo que no enfrentamos una sola causa raíz. –