it-swarm.com.de

Testen von Bedingungen mit mehreren Threads

Lesen Sie die Kommentare zu diesem Antwort , speziell:

Nur weil Sie keinen Test schreiben können, heißt das nicht, dass er nicht kaputt ist. Undefiniertes Verhalten, das normalerweise wie erwartet funktioniert (C und C++ sind voll davon), Rennbedingungen, mögliche Neuordnung aufgrund eines schwachen Speichermodells ... - CodesInChaos vor 7 Stunden

@CodesInChaos Wenn es nicht reproduziert werden kann, kann der in 'fix' geschriebene Code auch nicht getestet werden. Und ungetesteten Code ins Leben zu rufen ist meiner Meinung nach ein schlimmeres Verbrechen - RhysW vor 5 Stunden

... habe ich mich gefragt, ob es gute allgemeine Möglichkeiten gibt, sehr selten sehr selten auftretende Produktionsprobleme auszulösen, die durch die Rennbedingungen im Testfall verursacht werden.

Nachdem ich seit ungefähr 1978 in diesem verrückten Geschäft war und fast die ganze Zeit im Embedded-Echtzeit-Computing verbracht hatte, arbeitete ich mit Multitasking-, Multithread- und Multi-Was auch-Systemen, manchmal mit mehreren physischen Prozessoren, und hatte mehr als meinen gerechten Anteil an Rennen gejagt Meine überlegte Meinung ist, dass die Antwort auf Ihre Frage recht einfach ist.

Nein.

Es gibt keinen guten allgemeinen Weg, um beim Testen eine Rennbedingung auszulösen.

Ihre einzige Hoffnung ist es, sie vollständig aus Ihrem System heraus zu entwerfen.

Wann und wenn Sie feststellen, dass jemand anderes einen hineingestopft hat, sollten Sie ihm einen Ameisenhaufen abstecken und ihn dann neu gestalten, um ihn zu beseitigen. Nachdem Sie seine Fauxpas (ausgesprochen f *** up) aus Ihrem System heraus entworfen haben, können Sie ihn von den Ameisen befreien. (Wenn die Ameisen ihn bereits verzehrt haben und nur Knochen zurücklassen, stellen Sie ein Schild mit der Aufschrift "Dies passiert mit Menschen, die die Rennbedingungen in das XYZ-Projekt aufnehmen!" Auf und lassen Sie ihn dort.)

89
John R. Strohm

Wenn Sie sich in der ms-Toolkette befinden. Ms Forschung hat ein Tool erstellt, das neue Interlevings für jeden Lauf erzwingt und fehlgeschlagene Läufe mit dem Namen Schach neu erstellen kann.

hier ist ein Video , das es in Gebrauch zeigt.

16
rerun

Das beste Werkzeug, das ich für diese Art von Problemen kenne, ist eine Erweiterung von Valgrind namens Helgrind .

Grundsätzlich simuliert Valgrind einen virtuellen Prozessor und führt Ihre Binärdatei (unverändert) darauf aus, sodass jeder einzelne Zugriff auf den Speicher überprüft werden kann. Unter Verwendung dieses Frameworks ruft das Helgrind-Überwachungssystem auf, um zu schließen, wenn ein Zugriff auf eine gemeinsam genutzte Variable durch einen gegenseitigen Ausschlussmechanismus nicht ordnungsgemäß geschützt ist. Auf diese Weise kann ein theoretischer Rassenzustand erkannt werden, auch wenn er nicht tatsächlich eingetreten ist.

Intel verkauft ein sehr ähnliches Tool namens Intel Inspector .

Diese Tools liefern hervorragende Ergebnisse, aber Ihr Programm wird während der Analyse erheblich langsamer.

16
Julien

Um einen Multithreading-Fehler aufzudecken, müssen verschiedene Ausführungsthreads gezwungen werden, ihre Schritte in einer bestimmten verschachtelten Reihenfolge auszuführen. Normalerweise ist dies ohne manuelles Debuggen oder Manipulieren des Codes schwierig, um eine Art "Handle" zur Steuerung dieser Verschachtelung zu erhalten. Das Ändern von Code, der sich unvorhersehbar verhält, beeinflusst jedoch häufig diese Unvorhersehbarkeit. Daher ist dies schwer zu automatisieren.

Ein netter Trick wird von Jaroslav Tulach in Practical API Design beschrieben: Wenn Sie Protokollanweisungen im fraglichen Code haben, manipulieren Sie den Consumer dieser Protokollierungsanweisungen (z. B. ein injiziertes Pseudo-Terminal), so dass die einzelnen Protokollnachrichten in einer bestimmten Reihenfolge basierend auf ihrem Inhalt akzeptiert werden. Auf diese Weise können Sie die Verschachtelung von Schritten in verschiedenen Threads steuern, ohne dem Produktionscode etwas hinzufügen zu müssen, das noch nicht vorhanden ist.

8
Kilian Foth

Es gibt keine Möglichkeit, absolut sicher zu sein, dass verschiedene Arten von undefiniertem Verhalten (insbesondere Rennbedingungen) nicht existieren.

Es gibt jedoch eine Reihe von Tools, die eine gute Anzahl solcher Situationen aufzeigen. Möglicherweise können Sie nachweisen, dass derzeit ein Problem mit solchen Tools besteht, obwohl Sie nicht nachweisen können, dass Ihr Fix gültig ist.

Einige interessante Werkzeuge für diesen Zweck:

Valgrind ist ein Speicherprüfer. Es findet Speicherlecks, liest nicht initialisierten Speicher, verwendet baumelnde Zeiger und Zugriffe außerhalb der Grenzen.

Helgrind ist ein Thread-Sicherheitsprüfer. Es findet Rennbedingungen.

Beide arbeiten mit dynamischer Instrumentierung, d. H. Sie nehmen Ihr Programm so wie es ist und führen es in einer virtualisierten Umgebung aus. Dies macht sie unauffällig, aber langsam.

UBSan ist eine undefinierte Verhaltensprüfung. Es werden verschiedene Fälle von undefiniertem Verhalten in C und C++ gefunden, z. B. Ganzzahlüberläufe, Verschiebungen außerhalb des Bereichs und ähnliches.

MSan ist ein Speicherprüfer. Es hat ähnliche Ziele wie Valgrind.

TSan ist ein Thread-Sicherheitsprüfer. Es hat ähnliche Ziele wie Helgrind.

Diese drei sind in den Clang-Compiler integriert und generieren beim Kompilieren Code. Dies bedeutet, dass Sie sie in Ihren Erstellungsprozess integrieren müssen (insbesondere müssen Sie mit Clang kompilieren), was die anfängliche Einrichtung erheblich erschwert als * Grind, andererseits jedoch einen viel geringeren Laufzeitaufwand.

Alle von mir aufgelisteten Tools funktionieren unter Linux und einige unter MacOS. Ich denke noch keine zuverlässige Arbeit unter Windows.

6
Sebastian Redl

Es scheint, dass die meisten Antworten hier diese Frage als "Wie erkenne ich automatisch die Rennbedingungen?" Verwechseln. wenn die Frage wirklich lautet: "Wie reproduziere ich die Rennbedingungen beim Testen, wenn ich sie finde?"

Der Weg, dies zu tun, besteht darin, eine Synchronisation in Ihren Code einzuführen, die nur zum Testen verwendet wird. Wenn beispielsweise eine Ereignisbedingung auftritt, wenn Ereignis X zwischen Ereignis A und Ereignis B auftritt, schreiben Sie zum Testen Ihrer Anwendung einen Code, der darauf wartet, dass Ereignis X nach Ereignis A eintritt. Sie werden wahrscheinlich eine Möglichkeit benötigen, damit Ihre Tests mit Ihrer Anwendung kommunizieren können, um dies mitzuteilen ("Hey, ich teste dieses Ding, also warten Sie auf dieses Ereignis an diesem Ort").

Ich verwende node.js und mongo, wobei einige Aktionen das Erstellen konsistenter Daten in mehreren Sammlungen umfassen. In diesen Fällen rufen meine Komponententests die Anwendung auf, um ihr mitzuteilen, dass "Warten auf Ereignis X eingerichtet" wurde. Sobald die Anwendung es eingerichtet hat, wird der Test für Ereignis X ausgeführt und die Tests werden anschließend angezeigt die Anwendung ("Ich bin mit dem Warten auf Ereignis X fertig"), damit der Rest der Tests normal ausgeführt wird.

Die Antwort hier erklärt diese Art von Dingen im Zusammenhang mit Python im Detail: https://stackoverflow.com/questions/19602535/how-can-i-reproduce-the-race-conditions-in-this- Python-Code-zuverlässig

2
B T