definicion - que es multithreading en programacion
Analizando programas multiproceso (7)
Como punto de partida, estaría tentado de agregar mensajes de registro de seguimiento en puntos estratégicos dentro de su aplicación. Esto le permitirá analizar cómo interactúan sus hilos sin peligro de que el acto de observar los hilos modifique su comportamiento (como podría ser el caso con la depuración paso a paso). Mi experiencia es con la plataforma .NET y mi herramienta de registro favorita sería log4net ya que es gratuita, tiene amplias opciones de configuración y, si es sensato en la forma en que implementa su registro, no obstaculizará notablemente el rendimiento de su aplicación. Alternativamente, existe .NET construida en la clase Debug (o Trace) en el espacio de nombres System.Diagnostics.
Tenemos una base de código que tiene varios años y todos los desarrolladores originales se han ido. Utiliza muchos, muchos hilos, pero sin un diseño aparente o principios arquitectónicos comunes. Cada desarrollador tenía su propio estilo de programación multiproceso, por lo que algunos hilos se comunican entre sí utilizando colas, algunos datos de bloqueo con exclusión mutua, algunos bloqueos con semáforos, algunos utilizan mecanismos de IPC del sistema operativo para comunicaciones dentro del proceso. No hay documentación de diseño, y los comentarios son escasos. Es un desastre, y parece que cada vez que tratamos de refactorizar el código o agregar nuevas funcionalidades, presentamos bloqueos u otros problemas.
Entonces, ¿alguien sabe de alguna herramienta o técnica que pueda ayudar a analizar y documentar todas las interacciones entre los hilos? FWIW, la base de código es C ++ en Linux, pero estaría interesado en conocer las herramientas para otros entornos.
Actualizar
Aprecio las respuestas recibidas hasta ahora, pero esperaba algo más sofisticado o sistemático que un consejo que es esencialmente "agregar mensajes de registro, descubrir qué está pasando y solucionarlo". Existen muchas herramientas para analizar y documentar el flujo de control en programas de un solo hilo; ¿No hay nada disponible para programas de subprocesos múltiples?
Consulte también Depuración de aplicaciones multiproceso
Primero me centraría en los bloqueos de memoria compartida (los mutex y los semáforos) ya que es muy probable que causen problemas. Mire qué estado está siendo protegido por bloqueos y luego determine qué estado está bajo la protección de varios bloqueos. Esto le dará una sensación de conflictos potenciales. Observe las situaciones en las que el código que contiene un bloqueo llama a los métodos (no olvide los métodos virtuales). Intente eliminar estas llamadas donde sea posible (reduciendo el tiempo de retención).
Dada la lista de mutexes que se guardan y una idea aproximada del estado que protegen, asigne un orden de bloqueo (es decir, el mutex A siempre debe tomarse antes del mutex B). Intenta forzar esto en el código.
Vea si puede combinar varios bloqueos en uno si la concurrencia no se ve afectada adversamente. Por ejemplo, si el mutex A y B parece que pueden tener bloqueos y un esquema de ordenamiento no se realiza fácilmente, combínelos inicialmente en un bloqueo.
No va a ser fácil, pero estoy simplificando el código a expensas de la concurrencia para manejar el problema.
Una cosa a tener en cuenta al usar log4net o una herramienta similar es que cambian el tiempo de la aplicación y a menudo pueden ocultar las condiciones de carrera subyacentes. Tuvimos un código mal escrito para depurar e introdujimos el registro y esto realmente eliminó las condiciones de carrera y los interbloqueos (o redujo en gran medida su frecuencia).
Este es un problema realmente difícil para las herramientas automatizadas. Es posible que desee examinar el modelo que verifica su código. No espere resultados mágicos: los inspectores modelo son muy limitados en cuanto a la cantidad de código y la cantidad de hilos que pueden verificar efectivamente.
Una herramienta que podría funcionar para usted es CHESS (aunque desafortunadamente solo para Windows). BLAST es otra herramienta bastante poderosa, pero es muy difícil de usar y no puede manejar C ++. Wikipedia también enumera StEAM , del que no había oído hablar antes, pero parece que podría funcionar para usted:
StEAM es un corrector de modelos para C ++. Detecta interbloqueos, fallas de segmentación, variables fuera de rango y bucles no terminales.
Alternativamente, probablemente sería de mucha ayuda intentar converger el código hacia un pequeño número de esquemas de sincronización bien definidos (y preferiblemente de alto nivel). Mezclar bloqueos, semáforos y monitores en la misma base de código es buscar problemas.
Invierta en una copia de VTune de Intel y sus herramientas de generación de perfiles. Le dará un sistema y una vista del nivel de fuente del comportamiento de la secuencia. Ciertamente, no va a autodocumentar la cosa por usted, pero debería ser una ayuda real al menos para visualizar lo que está sucediendo en diferentes circunstancias.
Creo que hay una versión de prueba que puede descargar, por lo que puede valer la pena intentarlo. Solo he usado la versión de Windows, pero al mirar la página web de VTune también tiene una versión de Linux.
En Java, tiene opciones como FindBugs (para el análisis de bytecode estático) para encontrar ciertos tipos de sincronización inconsistente, o los muchos analizadores de hilos dinámicos de compañías como Coverity, JProbe, OptimizeIt, etc.
¿No puede UML ayudarte aquí?
Si realiza una ingeniería inversa de su base de código en UML , entonces debería ser capaz de dibujar diagramas de clase que muestren las relaciones entre sus clases. A partir de las clases cuyos métodos son los puntos de entrada de subprocesos, puede ver qué subproceso usa qué clase. De acuerdo con mi experiencia con Rational Rose , esto podría lograrse usando el método de arrastrar y soltar; si no hay relación entre la clase agregada y las anteriores, entonces la clase agregada no se usa directamente por el hilo que comenzó con el método con el que comenzó el diagrama. Esto debería darte pistas sobre el papel de cada hilo.
Esto también mostrará los "objetos de datos" que se comparten y los objetos que son específicos de la secuencia.
Si dibuja un diagrama de clase grande y elimina todos los "objetos de datos", entonces debería poder diseñar ese diagrama como nubes, cada nube como un hilo o un grupo de hilos, a menos que el acoplamiento y la cohesión de la base del código sea horrible.
Esto solo te dará una parte del rompecabezas, pero podría ser útil; Solo espero que tu código base no sea demasiado complicado o demasiado "de procedimiento", en cuyo caso ...