Leyendo los comentarios a esta respuesta , específicamente:
El hecho de que no puedas escribir un examen no significa que no esté roto. Comportamiento indefinido que generalmente funciona como se esperaba (C y C ++ están llenos de eso), condiciones de carrera, posible reordenamiento debido a un modelo de memoria débil ... - CodesInChaos hace 7 horas
@CodesInChaos si no se puede reproducir, entonces el código escrito para 'arreglar' 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 de producción muy poco frecuentes causados por las condiciones de carrera en el caso de prueba.
testing
multithreading
Dan Neely
fuente
fuente
Respuestas:
Después de haber estado en este negocio loco desde aproximadamente 1978, haber pasado casi todo ese tiempo en computación integrada en tiempo real, trabajando en sistemas multitarea, multiproceso, lo que sea, a veces con múltiples procesadores físicos, después de haber perseguido más de mi parte de la raza. condiciones, mi opinión considerada 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.
Su ÚNICA esperanza es diseñarlos completamente fuera de su sistema.
Cuando y si descubres que alguien más ha metido uno, debes replantearle un hormiguero y luego rediseñarlo para eliminarlo. Después de haber diseñado su faux pas (pronunciado f *** up) fuera de su sistema, puede ir a liberarlo de las hormigas. (Si las hormigas ya lo han consumido, dejando solo huesos, coloque un letrero que diga "¡Esto es lo que le sucede a las personas que ponen las condiciones de carrera en el proyecto XYZ!" Y DEJELO AQUÍ).
fuente
Si estás en la cadena de herramientas ms. La investigación de Ms ha creado una herramienta que forzará nuevas intercalaciones para cada carrera y puede recrear carreras fallidas llamadas ajedrez .
Aquí hay un video que lo muestra en uso.
fuente
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, para que pueda verificar cada acceso a la memoria. Usando ese marco, el sistema de vigilancia Helgrind llama a inferir cuando un acceso a una variable compartida no está protegido adecuadamente 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 dan excelentes resultados, pero su programa será considerablemente más lento durante el análisis.
fuente
Exponer un error de subprocesos múltiples requiere forzar diferentes subprocesos de ejecución para realizar sus pasos en un orden intercalado 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 "control" para controlar este entrelazado. Pero cambiar el código que se comporta de manera impredecible a menudo influirá en esa imprevisibilidad, por lo que es difícil de automatizar.
Jaroslav Tulach describe un buen truco en Practical API Design : si tiene declaraciones de registro en el código en cuestión, manipule al consumidor de esas declaraciones de registro (por ejemplo, un pseudo terminal inyectado) para que acepte los mensajes de registro individuales en un determinado orden basado en su contenido. Esto le permite controlar la intercalación de pasos en diferentes subprocesos sin tener que agregar nada al código de producción que aún no está allí.
fuente
No hay forma de estar absolutamente seguros de que no existan varios tipos de comportamiento indefinido (en particular las condiciones de carrera).
Sin embargo, hay una serie de herramientas que muestran una buena cantidad de tales situaciones. Es posible que pueda probar que existe un problema actualmente con tales herramientas, aunque no puede probar que su solución es válida.
Algunas herramientas interesantes para este propósito:
Valgrind es un verificador de memoria. Encuentra pérdidas de memoria, lecturas de memoria no inicializada, usos de punteros colgantes y accesos fuera de límites.
Helgrind es un verificador de seguridad de hilos. Encuentra condiciones de carrera.
Ambos funcionan mediante instrumentación dinámica, es decir, toman su programa tal cual y lo ejecutan en un entorno virtualizado. Esto los hace no intrusivos, pero lentos.
UBSan es un verificador de comportamiento indefinido. Encuentra varios casos de comportamiento indefinido de C y C ++, como desbordamientos de enteros, cambios fuera de rango y cosas similares.
MSan es un verificador de memoria. Tiene objetivos similares a los de Valgrind.
TSan es un verificador de seguridad de hilos. Tiene objetivos similares a Helgrind.
Estos tres están integrados en el compilador de Clang y generan código en tiempo de compilación. Esto significa que debe integrarlos en su proceso de compilación (en particular, debe 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. No creo que ningún trabajo en Windows sea confiable todavía.
fuente
Parece que la mayoría de las respuestas aquí confunden esta pregunta con "¿cómo detecto automáticamente las condiciones de 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 ocurre una condición de carrera cuando ocurre el Evento X entre el Evento A y el Evento B, entonces para probar su aplicación, escriba un código que espere a que ocurra el Evento X 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 ("oye, estoy probando esto, así que espere este evento en esta ubicación").
Estoy usando node.js y mongo, donde algunas acciones implican la creación de datos consistentes en múltiples colecciones. En estos casos, las pruebas de mi unidad 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, se ejecutará la prueba para el evento X, y las pruebas le indicarán posteriormente la aplicación ("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: https://stackoverflow.com/questions/19602535/how-can-i-reproduce-the-race-conditions-in-this-python-code- seguramente
fuente