Ich versuche Actor-Berechnungsmodell über Threads in C ++ zu implementieren, indem ich boost :: thread verwende. Aber das Programm löst während der Ausführung eine seltsame Ausnahme aus. Ausnahme ist nicht stabil und manchmal funktioniert das Programm korrekt.
Dort mein Code:
actor.hpp
%Vor%actor.cpp
%Vor% Die Ausnahme, die geworfen wird, ist boost :: thread_interrupted in int rc = future.get();
line. Aber form boost docs kann ich nicht von dieser Ausnahme halten. Docs sagt
Wird ausgelöst: - boost :: thread_interrupted, wenn das mit * verknüpfte Ergebnis zum Zeitpunkt des Aufrufs noch nicht fertig ist und der aktuelle Thread unterbrochen ist.
Aber mein Worker-Thread kann nicht unterbrochen sein.
Als ich gdb benutzt habe und "catch throw" gesetzt habe, sehe ich, dass die Rückverfolgung wie
aussiehtthrow thread_interrupted
boost :: detail :: interruption_checker :: check_for_interruption
boost :: detail :: interrupt_checker :: interrupt_checker
boost :: condition_variable :: wait
boost :: detail :: future_object_base :: wait_internal
boost :: detail :: future_object_base :: wait
boost :: detail :: future_object :: get
boost :: unique_future :: get
Ich habe Boost-Quellen untersucht, kann aber nicht herausfinden, warum interruption_checker entschieden hat, dass der Worker-Thread unterbrochen wird.
Also jemand C ++ Guru, bitte hilf mir. Was muss ich tun, um den richtigen Code zu erhalten? Ich benutze:
boost 1_53
Linux Version 2.6.18-194.32.1.el5 Red Hat 4.1.2-48
gcc 4.7
BEARBEITEN
Es wurde behoben! Danke an Evgeny Panasyuk und Lazin. Das Problem war in TLS Management. boost :: thread und boost :: thread_specific_ptr verwenden gleicher TLS-Speicher für ihre Zwecke. In meinem Fall gab es ein Problem wann Beide haben versucht, diesen Speicher bei der Erstellung zu ändern (Leider habe ich hat nicht verstanden, warum im Detail es passiert). So wurde TLS beschädigt.
Ich habe boost :: thread_specific_ptr aus meinem Code mit __thread ersetzt angegebene Variable.
Offtop: Während des Debugging habe ich Speicherfehler in der externen Bibliothek gefunden und repariere es =)
.
EDIT 2 Ich habe das genaue Problem ... Es ist ein Fehler in GCC =) Das _GLIBCXX_DEBUG-Kompilierungsflag unterbricht ABI. Sie können die Diskussion über Boost Bugtracker sehen: Ссылка
Ich habe mehrere Fehler gefunden:
Actor::workerThread
function wird doppelt auf d_jobQueueMutex
entsperrt. Das erste Entsperren ist manuell d_jobQueueMutex.unlock();
, das zweite ist im Destruktor von boost::unique_lock<boost::mutex>
.
Sie sollten eine Entsperrung verhindern, zum Beispiel release Zuordnung zwischen unique_lock
und mutex
:
Oder fügen Sie einen zusätzlichen Codeblock + default-constructed Job
hinzu.
Es ist möglich, dass workerThread
niemals die folgende Schleife verlässt:
Stellen Sie sich folgenden Fall vor: d_jobQueue
ist leer, Actor::~Actor()
wird aufgerufen, setzt Flag und benachrichtigt den Arbeitsthread:
workerThread
wacht in der while-Schleife auf, sieht, dass die Warteschlange leer ist und wieder schläft.
Es ist üblich, einen speziellen letzten Job zu senden, um den Worker-Thread zu stoppen:
%Vor% In diesem Fall muss d_keepWorkerRunning
nicht atomar sein.
BEARBEITEN :
Ich habe den Code für die Ereigniswarteschlange in Ihr Beispiel eingefügt.
Sie haben eine gleichzeitige Warteschlange in EventQueueImpl
und Actor
, aber für verschiedene Typen. Es ist möglich, einen gemeinsamen Teil in die separate Entity concurrent_queue<T>
zu extrahieren, die für jeden Typ funktioniert. Es wäre viel einfacher, die Warteschlange an einer Stelle zu debuggen und zu testen, als Fehler in verschiedenen Klassen zu erfassen.
Sie können also versuchen, concurrent_queue<T>
(auf Coliru)
Das ist nur eine Vermutung. Ich denke, dass ein Code tatsächlich boost heißen kann: : tread :: interrupt () . Sie können einen Haltepunkt für diese Funktion festlegen und sehen, welcher Code dafür verantwortlich ist. Sie können in execJobSync
auf Unterbrechung testen:
Der verdächtigste Code in diesem Fall ist ein Code, der auf ein Thread-Objekt verweist.
Es ist eine gute Übung, die boost :: Thread-Code-Unterbrechung trotzdem bewusst zu machen. Es ist auch möglich, Unterbrechung zu deaktivieren für einige Bereiche.
Wenn dies nicht der Fall ist, müssen Sie den Code überprüfen, der mit lokalem Threadspeicher arbeitet, da das Flag für die Threadunterbrechung im TLS gespeichert ist. Vielleicht schreibt Ihr Code es um. Sie können die Unterbrechung vor und nach einem solchen Codefragment überprüfen.
Eine andere Möglichkeit ist, dass dein Speicher korrupt ist. Wenn kein Code boost :: thread :: interrupt () aufruft und Sie nicht mit TLS arbeiten. Dies ist der schwierigste Fall, versuchen Sie, einen dynamischen Analysator zu verwenden - Valgrind oder Clam Memory Sanitizer.
Offtopic: Wahrscheinlich müssen Sie einige gleichzeitige Warteschlangen verwenden. std :: queue wird wegen hoher Speicherkonkurrenz sehr langsam sein und Sie werden mit schlechter Cache-Leistung enden. Eine gute gleichzeitige Warteschlange ermöglicht es Ihrem Code, Elemente parallel in die Warteschlange einzuordnen oder aus der Warteschlange zu entfernen.
Darsteller ist auch nicht etwas, das willkürlichen Code ausführen soll. Die Actor-Warteschlange muss einfache Nachrichten empfangen, keine Funktionen! Du schreibst eine Jobwarteschlange :) Du musst dir ein Schauspieler-System wie Akka oder libcpa .
Tags und Links c++ multithreading boost actor