Multithreading Problem, Valgrind zu lahm
-
Hallo,
ich habe ein etwas groesseres Programm, bei dem mehrere Threads auf Listen zugreifen.
Nun bekomme ich an immer anderen Stellen einen segmentation fault. Gdb zeigt mir dass es beim anlegen neuer Objekte passiert.
Meine Vermutung ist dass sich da zwei Threads in die quere kommen und sich irgendwo illegate reads oder writes verstecken.
Bisher habe ich soetwas mit Valgrind geloest, doch wenn ich das Programm mit Valgrind ausfuehre, so laeuft das Ganze nur noch mit halber Geschwindigkeit und der Fehler tritt nicht mehr auf
Kennt jemand eine Moeglichkeit die fehlerhaften Speicherzugriffe auf eine andere Moeglichkeit zu ermitteln?
Vielen Dank,
FReAK
-
intel bietet einen Satz an Tools an. Aber ob die in Deinem Fall einsetzbar sind, hängt von Platform, Entwicklungsumgebung und nicht zuletzt vom Geldbeutel ab.
Hast Du den Zugriff auf die Listen den mit Mutex gesichert?
-
FReAK La Marsch schrieb:
Gdb zeigt mir dass es beim anlegen neuer Objekte passiert.
Ich vermute mal, dass du wie gastgast schon sagt, keinen Mutex (konsequent) verwendest.
Die komplette STL ist nicht-threadsafe...Du wirst eventuell in zwei Threads gleichzeitig ein Objekt in einen vector
(oder wirklich list?) einfügen und da nicht genug Speicher vorhanden ist, werden deine Daten in einen anderen Speicherbereich verlagert und der andere Thread versucht das Objekt noch im ursprünglichen Speicherbereich zu erstellen, der aber nicht mehr zu deinem Programm gehört.Ist es denn ein Objekt-Typ, der in einem vector verwendet wird?
EDIT: Liege ich mit der Annahme, dass du std::vector verwendest, wenigstens richtig
-
Hallo,
vector ist fast richtig, ich verwende deque, aber auch eine eigene verlinkte Liste (hat ein paar extra Regeln fuer das Einfuegen von Elementen). Aber beides ist sicherlich nicht thread safe und deswegen ist alles mit Mutexen gesichert.
Ich habe auch versucht die gesicherten Bereiche so klein wie moeglich zu halten, gebe also die Mutex immer wieder frei. Es kann schon sein, dass ich da einen Denkfehler drin habe, aber da der Segmentation fault immer auftritt wenn ein neues Objekt mit new() angelegt wird (aber nicht immer an der gleichen Stelle im Code) vermute ich, dass meine verlinkte Liste da kurz vorher den Speicher zerschossen hat.
Bisher hat mir da Valgrind immer gut geholfen, aber das bremst mein Programm nun so aus, dass das Problem nicht mehr auftritt (lief die ganze Nacht durch in der Hoffnung doch eine Absturz zu bekommen)
Ich entwickel mit Eclipse und gcc unter Linux und hab leider kein extra Budget fuer tolle Tools. Ich bin aber weiterhin fue jeden Tipp dankbar, da mir der printf-Debugger auch noch nicht weitergeholfen hat.
-
Vielleicht kannst du ja den Absturz etwas provozieren, damit er auch mit valgrind auftritt...
Es ist vielleicht eine blöde Idee, aber du kannst ja zu Beginn des entsprechenden Konstruktors ein yield für den aktuellen Thread aufrufen, damit andere Threads an die Reihe kommen.
Das kannst du z.B. mit boost machen:
http://www.boost.org/doc/libs/1_47_0/doc/html/thread/thread_management.html#thread.thread_management.thread.yieldAnsonsten kann man es noch drastischer machen und ein yield am Ende eines überschriebenen new-Operators machen.
Ja... Ich weiß... Kranke Ideen, aber könnte evtl. bei der Fehlersuche helfen
-
Kannst Du mal den Code posten, der den Zugriff auf die Liste sichert?
Ich vermute immer noch, dass da der Haken liegt. Das Einfachste ist in der Regel, um die std:: Klasse einen Wrapper drum zu legen, der die Zugriffe per Mutex sequentialisiert.
-
Du kannst probieren durch aktives Warten ala for (i = 0; i < 1000; i++); in deinem Thread den Fehler herauszuprovozieren, sofern du eine Ahnung hast wo ungefähr der Fehler ist.
Alternativ spiele mal in Gedanken mit deinen Threads herum und schaue mal ob du so den Fehler findest. Sequenzdiagramme sind dabei ein Hilfsmittel. Kann es beispielsweise passieren das zwei Threads gleichzeitig auf deine Liste zugreifen ? ...
-
Hallo und danke fuers mitdenken.
Zum Posten ist mein Code leider etwas zu komplex (sonst haette ich vermutlich auch nicht das Problem).
Wie gesagt ich hab einige Threads die parallel auf Listen arbeiten und somit viele Stellen an denen ich eine Mutex sperre und wieder freigebe.
Die Vorschlaege zum herbeifuehren von Absturzen funktionieren leider nicht, da ich die Stelle nicht finde wo ich die Funktion verlangsamen muss, bzw. mit yield unterbrechen.
Wenns kein Tool gibt das mir da helfen kann muss ich wohl zurueck zum Zeichenbrett ...
-
Also meines Erachtens solltest Du nur eine Stelle haben an denen beim Zugriff auf die Liste ein mutex gesperrt bzw freigegeben wird: In der Liste! Oder habe ich das was falsch verstanden?
-
@gastgast: prinzipiell hast du recht, wenn man es sauber strukturiert, dann kümmert sich die Liste selbst um das locking. Bei mir beinhaltet die Liste aber pointer und deswegen müssen die Consumer da signalisieren wie lange die Liste gesperrt sein muss.
Ich hab mein ganzes Design überarbeitet und nun neue Listen bei denen das Problem nicht mehr auftritt.
Danke für eure Mithilfe,
FReAK