Programación en C: Depuración con pthreads


Una de las cosas más difíciles a las que me ajusté inicialmente fue mi primera experiencia intensa programando con pthreads 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 centraban 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.

P.d. Hago mi C programación usando gcc en linux, pero no dejes que eso necesariamente restrinja tu respuesta

Author: JoeCool, 2009-06-11

8 answers

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

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

De todos modos, valgrind me ha ahorrado incontables horas de depuración (aunque no todas:).

 29
Author: Laurynas Biveinis,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-06-11 19:25:55

Una de las cosas que le sorprenderá acerca de depurar programas enhebrados es que a menudo encontrará que el error cambia, o incluso desaparece cuando agrega printf o ejecuta el programa en el depurador (coloquialmente conocido como Heisenbug).

En un programa enhebrado, un Heisenbug generalmente significa que tienes una condición de carrera . Un buen programador buscará variables o recursos compartidos que dependan del orden. Un programador de mierda tratará de arreglarlo ciegamente con el sueño() instrucción.

 7
Author: T.E.D.,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-06-11 13:49:57

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

 2
Author: luke,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-06-11 16:26:28

En la fase de 'pensar', antes de empezar a codificar, utilice el concepto de Máquina de Estados. Puede hacer el diseño mucho más claro.

Printf puede ayudarle a entender la dinámica de su programa. Pero desordenan el código fuente, así que usa una macro DEBUG_OUT () y en su definición habilítala con una bandera booleana. Mejor aún, establezca / borre esta bandera con una señal que envíe a través de 'kill-USR1'. Envíe 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.

 2
Author: rleir,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2010-02-13 15:17:25

Mi enfoque para la depuración multihilo es similar al subproceso simple, pero generalmente se pasa más tiempo en la fase de pensamiento:

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

  2. Determinar qué tipo de resultados podrían esperarse si la teoría es cierta.

  3. Si es necesario, agregue código que pueda refutar o verificar sus resultados y 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 alrededor del código sospechoso. Entonces 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 identificar la 'pistola humeante'.

Como dije, los mismos pasos se aplican a la depuración de un solo subproceso, aunque es demasiado fácil saltar a un depurador y hacerlo. La depuración multihilo requiere una comprensión mucho más fuerte del código, ya que generalmente encuentro que el código multihilo en ejecución a través de un depurador no produce nada útil.

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

 1
Author: Marc Bernier,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-06-12 01:22:23

Me desarrollo en un mundo exclusivamente multihilo y de alto rendimiento, así que aquí está la práctica general que uso.

Diseño - la mejor optimización es un algoritmo mejor:

1) Divide tus funciones en piezas LÓGICAMENTE separables. Esto significa que una llamada hace "A" y SOLO " A " - no A entonces B entonces C...
2) NO HAY EFECTOS SECUNDARIOS: Abolir todas las variables abiertamente globales, estáticas o no. Si no puede eliminar completamente los efectos secundarios, aíslelos en algunos lugares (concéntrelos en el código).
3) Hacer tantos componentes aislados REENTRANTE como sea posible. Esto significa que son apátridas-toman todas sus entradas como constantes y solo manipulan los parámetros declarados, lógicamente constantes para producir la salida. Pase-por-valor en lugar de referencia siempre que pueda.
4) Si tiene estado, haga una separación clara entre los subconjuntos sin estado y la máquina de estado real. Idealmente, la máquina de estados será una sola función o clase manipulando componentes sin estado.

Depuración:

Los errores de enhebrado tienden a venir en 2 sabores amplios: razas y bloqueos. Como regla general, los puntos muertos son mucho más deterministas.

1) ¿Ves corrupción de datos?: YES = > Probably a race.
2) ¿Surge el error en CADA carrera o solo en algunas carreras?: YES = > Likely a deadlock (races are generally non-deterministic).
3) ¿El proceso se cuelga alguna vez?: YES => There's a deadlock somewhere. Si solo se cuelga a veces, es probable que tenga una carrera demasiado.

Los puntos de interrupción a menudo actúan como primitivas de sincronización en el código, porque son lógicamente similares: obligan a la ejecución a detenerse en el contexto actual hasta que otro contexto (usted) envíe una señal para reanudar. Esto significa que debe ver cualquier punto de interrupción que tenga en el código como alterar su comportamiento de subprocesos mufti, y los puntos de interrupción afectarán las condiciones de carrera, pero (en general)no los bloqueos.

Como regla general, esto significa que debe eliminar todos los puntos de interrupción, identificar el tipo de error, LUEGO reintroducirlos a intentar solucionarlo. De lo contrario, simplemente distorsionan las cosas aún más.

 1
Author: user3726672,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-07-17 17:15:20

Tiendo a usar muchos puntos de interrupción. Si en realidad no se preocupan por la función de hilo, pero se preocupan por sus efectos secundarios, un buen momento para comprobarlos podría ser justo antes de que salga o vuelva a su estado de espera o cualquier otra cosa que esté haciendo.

 0
Author: kbyrd,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-06-11 13:34:34

Cuando empecé a hacer programación multiproceso I... dejó de usar 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 programar multihilo sin errores. Si no puede evitar dependencias de bloqueo complejas, entonces es fácil comprobar si son cíclicas - espere hasta que el programa se cuelgue y compruebe los stacktraces usando 'pstack'. Puede romper los bloqueos cíclicos introduciendo algunos hilos nuevos y comunicación asíncrona búfer.

Use aserciones, y asegúrese de escribir unittests singlethreaded para componentes particulares de su software; luego puede ejecutarlos en debugger si lo desea.

 0
Author: pafinde,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-09-19 20:28:08