Probando condiciones de carrera de múltiples hilos

52

Leer los comentarios a esta respuesta , específicamente:

  

El hecho de que no puedas escribir una prueba no significa que no esté roto. Comportamiento indefinido que normalmente funciona como se espera (C y C ++ están llenos de eso), condiciones de carrera, reordenamiento potencial debido a un modelo de memoria débil ... - CodesInChaos 7 Hace horas

  

@CodesInChaos si no se puede reproducir, el código escrito para "corregir" tampoco se puede probar. Y poner el código no probado en vivo es un crimen peor en mi opinión - RhysW hace 5 horas

... me hace preguntarme si hay alguna buena forma general de desencadenar constantemente problemas muy frecuentes en la producción causados por condiciones de carrera en el caso de prueba.

    
pregunta Dan Neely 25.04.2013 - 16:25

6 respuestas

80

Después de haber estado en este negocio loco desde aproximadamente 1978, haber pasado casi todo ese tiempo en sistemas integrados de computación en tiempo real, trabajo multitarea, multihilo, sistemas multiprocesos, a veces con múltiples procesadores físicos, habiendo perseguido más que mi feria Por lo que respecta a las condiciones de la carrera, mi opinión es que la respuesta a su pregunta es bastante simple.

No.

No hay una buena forma general de desencadenar una condición de carrera en las pruebas.

Tu ÚNICA esperanza es diseñarlos completamente fuera de tu sistema.

Cuando y si encuentras que alguien más ha rellenado uno, debes replantearlo un hormiguero y luego rediseñar para eliminarlo. Después de que hayas diseñado su faux pas (pronunciado f *** up) fuera de tu sistema, puedes liberarlo de las hormigas. (Si las hormigas ya lo han consumido, dejando solo huesos, ponga un letrero que diga "¡Esto es lo que les pasa a las personas que ponen las condiciones de la carrera en el proyecto XYZ!" Y DEJALO ELLOS.)

    
respondido por el John R. Strohm 25.04.2013 - 16:42
16

Si estás en la cadena de herramientas ms. La investigación de Ms ha creado una herramienta que forzará nuevas aplicaciones para cada ejecución y puede recrear las ejecuciones fallidas llamadas chess .

aquí hay un video que muestra su uso.

    
respondido por el rerun 25.04.2013 - 17:21
15

La mejor herramienta que conozco para este tipo de problemas es una extensión de Valgrind llamada Helgrind .

Básicamente, Valgrind simula un procesador virtual y ejecuta su binario (sin modificar) encima de él, para que pueda verificar cada acceso único a la memoria. Usando ese marco, Helgrind observa las llamadas al sistema para inferir cuando un acceso a una variable compartida no está debidamente protegido por un mecanismo de exclusión mutua. De esa manera puede detectar una condición de carrera teórica incluso si no ha sucedido realmente.

Intel vende una herramienta muy similar llamada Intel Inspector .

Estas herramientas ofrecen excelentes resultados, pero su programa será considerablemente más lento durante el análisis.

    
respondido por el Julien 25.04.2013 - 21:25
6

La exposición de un error de subprocesos múltiples requiere forzar diferentes subprocesos de ejecución para realizar sus pasos en un orden de entrelazado particular. Por lo general, esto es difícil de hacer sin la depuración manual o la manipulación del código para obtener algún tipo de "manejo" para controlar este entrelazado. Pero el cambio de código que se comporta de forma impredecible a menudo influirá en esa imprevisibilidad, por lo que es difícil de automatizar.

Jaroslav Tulach describe un buen truco en Diseño práctico de API : si tiene declaraciones de registro en el código en cuestión, manipule el consumidor de esas declaraciones de registro (por ejemplo, un pseudo-terminal inyectado) para que acepte los mensajes de registro individuales en un orden particular en función de su contenido. Esto le permite controlar el intercalado de pasos en diferentes subprocesos sin tener que agregar nada al código de producción que no esté allí.

    
respondido por el Kilian Foth 25.04.2013 - 16:37
6

No hay forma de estar absolutamente seguro de que no existen varios tipos de comportamiento indefinido (en particular, condiciones de carrera).

Sin embargo, hay una serie de herramientas que muestran un buen número de tales situaciones. Es posible que pueda probar que existe un problema actualmente con dichas herramientas, aunque no puede probar que su solución sea válida.

Algunas herramientas interesantes para este propósito:

Valgrind es un comprobador de memoria. Encuentra fugas de memoria, lecturas de memoria no inicializada, usos de punteros colgantes y accesos fuera de los límites.

Helgrind es un comprobador de seguridad de hilos. Encuentra condiciones de carrera.

Ambos trabajan por instrumentación dinámica, es decir, toman su programa como está y lo ejecutan en un entorno virtualizado. Esto los hace discretos, pero lentos.

UBSan es un verificador de comportamiento no definido. Encuentra varios casos de comportamiento indefinido de C y C ++, como desbordamientos de enteros, desplazamientos fuera de rango y cosas similares.

MSan es un comprobador de memoria. Tiene objetivos similares a los de Valgrind.

TSan es un comprobador de seguridad de hilos. Tiene objetivos similares a los de Helgrind.

Estos tres están integrados en el compilador Clang y generan código en tiempo de compilación. Esto significa que necesita integrarlos en su proceso de compilación (en particular, tiene que compilar con Clang), lo que los hace mucho más difíciles de configurar inicialmente que * grind, pero por otro lado tienen una sobrecarga de tiempo de ejecución mucho menor.

Todas las herramientas que enumeré funcionan en Linux y algunas de ellas en MacOS. Todavía no creo que ningún trabajo en Windows sea confiable.

    
respondido por el Sebastian Redl 26.04.2013 - 19:23
0

Parece que la mayoría de las respuestas aquí confunden esta pregunta con "¿cómo detecto automáticamente las condiciones de la carrera?" cuando la pregunta es realmente "¿cómo reproduzco las condiciones de carrera en las pruebas cuando las encuentro?"

La forma de hacerlo es introducir la sincronización en su código que se usa solo para pruebas. Por ejemplo, si se produce una condición de carrera cuando el Evento X ocurre entre el Evento A y el Evento B, entonces para probar su aplicación, escriba un código que espere a que el Evento X ocurra después de que ocurra el Evento A. Es probable que necesite alguna forma para que sus pruebas hablen con su aplicación para decirle ("hey estoy probando esto, así que espere este evento en esta ubicación").

Estoy usando node.js y mongo, donde algunas acciones involucran la creación de datos consistentes en múltiples colecciones. En estos casos, mis pruebas unitarias harán una llamada a la aplicación para decirle "configurar una espera para el Evento X", y una vez que la aplicación lo haya configurado, la prueba para el evento X se ejecutará y las pruebas posteriormente indicarán la aplicación ("ya terminé con la espera del evento X") para que el resto de las pruebas se ejecuten normalmente.

La respuesta aquí explica este tipo de cosas en detalle en el contexto de python: enlace

    
respondido por el B T 14.05.2015 - 22:06

Lea otras preguntas en las etiquetas

Comentarios Recientes

porque pueden suceder mucho más rápido. Los agentes de compilación se basan en proporcionar herramientas ricas a aquellos con habilidades de supervisión o gestión de productos que tienen mucha microgestión en lo que se debe hacer. StackShare define un grupo de desarrolladores para contribuir con tareas de ritmo duro que agregarán valor a el proceso de compilación para cualquier persona que tenga la experiencia técnica y el impulso para proporcionar un valor real a BuildAgent, como contribuyente activo. Aumentar... Lee mas