Programación en C: depuración con pthreads




multithreading debugging (7)

Una de las cosas más difíciles para mi ajuste inicial fue mi primera experiencia intensa de programación con subprocesos en C. Estaba acostumbrado a saber exactamente cuál sería la siguiente línea de código que se ejecutaría y la mayoría de mis técnicas de depuración se centraron en esa expectativa.

¿Cuáles son algunas buenas técnicas para depurar con pthreads en C? Puede sugerir metodologías personales sin herramientas adicionales, herramientas que use o cualquier otra cosa que lo ayude a depurar.

PD: hago mi programación en C usando gcc en linux, pero no permita que eso restrinja su respuesta necesariamente


Tiendo a usar muchos puntos de interrupción. Si realmente no te importa la función del hilo, pero sí te preocupes por sus efectos secundarios, un buen momento para verificarlos podría ser justo antes de que salga o vuelva a su estado de espera o lo que sea que esté haciendo.


Valgrind es una excelente herramienta para encontrar condiciones de carrera y mal uso de API. Mantiene un modelo de acceso a la memoria del programa (y quizás de los recursos compartidos) y detectará bloqueos faltantes incluso cuando el error sea benigno (lo que, por supuesto, significa que se volverá menos inesperadamente completamente inesperado en algún momento posterior).

Para usarlo, valgrind --tool=helgrind , aquí está su manual . Además, hay valgrind --tool=drd ( manual ). Helgrind y DRD utilizan diferentes modelos para detectar superposiciones pero posiblemente diferentes conjuntos de errores. También pueden ocurrir falsos positivos.

De todos modos, valgrind ha ahorrado innumerables horas de depuración (aunque no todas): para mí.


En la fase de "pensamiento", antes de comenzar a codificar, use el concepto de Máquina de Estado. Puede hacer el diseño mucho más claro.

Printf puede ayudarlo a comprender la dinámica de su programa. Pero saturan el código fuente, así que usan una macro DEBUG_OUT () y, en su definición, lo habilitan con una bandera booleana. Mejor aún, establezca / borre esta bandera con una señal que envíe a través de 'kill -USR1'. Enviar la salida a un archivo de registro con una marca de tiempo.

también considere usar assert (), y luego analice sus volcados de núcleo usando gdb y ddd.


Cuando comencé a hacer programación multiproceso, dejé de usar los depuradores. Para mí, el punto clave es una buena descomposición y encapsulación del programa.

Los monitores son la forma más fácil de programación multihilo sin errores. Si no puede evitar las dependencias de bloqueo complejas, es fácil verificar si son cíclicas; espere hasta que el programa se cuelgue y verifique los stacktraces usando 'pstack'. Puede romper bloqueos cíclicos introduciendo nuevos subprocesos y buffers de comunicación asíncrona.

Use afirmaciones y asegúrese de escribir pruebas de unidad de una sola secuencia para componentes particulares de su software; luego puede ejecutarlas en el depurador si lo desea.


Una de las cosas que le sorprenderán acerca de la depuración de programas de subprocesos es que a menudo encontrará los cambios de error, o incluso desaparece cuando agrega printf o ejecuta el programa en el depurador (conocido coloquialmente como Heisenbug ).

En un programa con hilos, un Heisenbug generalmente significa que tienes una condición de carrera . Un buen programador buscará variables compartidas o recursos que dependen de la orden. Un programador de mierda intentará arreglarlo a ciegas con declaraciones de sleep ().


La depuración de una aplicación multiproceso es difícil. Un buen depurador como GDB (con front-end DDD opcional) para el entorno * nix o el que viene con Visual Studio en Windows ayudará enormemente.


Mi enfoque de la depuración de subprocesos múltiples es similar al de un único subproceso, pero generalmente se gasta más tiempo en la fase de pensamiento:

  1. Desarrollar una teoría sobre lo que podría estar causando el problema.

  2. Determine qué tipo de resultados se pueden esperar si la teoría es cierta.

  3. Si es necesario, agregue un código que pueda refutar o verificar sus resultados y su teoría.

  4. Si tu teoría es cierta, arregla el problema.

A menudo, el "experimento" que prueba la teoría es la adición de una sección crítica o mutex en torno al código sospechoso. Luego trataré de reducir el problema reduciendo sistemáticamente la sección crítica. Las secciones críticas no siempre son la mejor solución (aunque a menudo puede ser la solución rápida). Sin embargo, son útiles para señalar la 'pistola humeante'.

Como dije, los mismos pasos se aplican a la depuración de un solo hilo, aunque es demasiado fácil simplemente saltar a un depurador y tenerlo. La depuración de subprocesos múltiples requiere una comprensión mucho más sólida del código, ya que generalmente encuentro que el código de subprocesos múltiples que se ejecuta a través de un depurador no es útil.

Además, hellgrind es una gran herramienta. El Thread Checker de Intel realiza una función similar para Windows, pero cuesta mucho más que hellgrind.





pthreads