Unser Projekt verwendet einige Boost-1.48-Bibliotheken auf verschiedenen Plattformen, einschließlich Windows, Mac, Android und IOS. Wir sind in der Lage, die IOS-Version des Projekts bei der Verwendung von IOS und nicht dauerhaft (nicht-trivial, aber zuverlässig) zum Absturz zu bringen Aus unserer Untersuchung sehen wir, dass ~ thread_data_base im thread_info des Threads aufgerufen wird, während der Thread noch läuft.
Dies scheint zu geschehen, weil der intelligente Zeiger eine Nullzählung erreicht, obwohl er offensichtlich still steht im Bereich in der thread_proxy-Funktion, die es erstellt und die angeforderte Funktion im Thread ausführt. Dies scheint in verschiedenen Fällen zu geschehen - der Call-Stack ist zwischen Abstürzen nicht identisch, obwohl es einige gibt Variationen, die üblich sind.
Nur um klar zu sein - das erfordert oft Code, der Hunderte von Threads erzeugt, obwohl es solche gibt nie mehr als 30 gleichzeitig laufen. Ich habe "Glück gehabt" und habe es sehr früh in der Lauf auch, aber das ist selten. Ich habe eine Version des Destruktors erstellt, die den Code auf frischer Tat ertappt:
in libs / thread / src / pthread / thread.cpp:
%Vor%Ich sollte beachten, dass ich (wie aus dem auskommentierten Code ersichtlich) zuvor überprüft hatte, dass void_thread_info == void_this, weil ich hat nur nach dem Fall gesucht, in dem sich die aktuelle thread_info des Threads selbst getötet hat. Ich habe auch Fälle gesehen, in denen der von get_current_thread_data zurückgegebene Wert nicht Null ist und anders als "das", was wirklich komisch ist.
Auch als ich diese Version des Codes zum ersten Mal schrieb, schrieb ich:
%Vor%und zur Laufzeit bekam ich eine sehr merkwürdige Ausnahme, die mir etwas über eine virtuelle Funktionstabelle sagte oder so ähnlich - ich erinnere mich nicht. Ich entschied, dass es versuchte, "==" für diesen Objekttyp aufzurufen und war damit unglücklich, also schrieb ich wie oben beschrieben um, indem ich die Umwandlungen als * getrennt machte Zeilen von Code. Das ist für mich ziemlich verdächtig. Ich bin nicht einer, der sich rennt, um Compiler zu beschuldigen, aber ...
Ich sollte auch beachten, dass wir den Destruktor gesehen haben, als wir die Falle gefangen haben ~ shared_count erscheint zweimal hintereinander auf dem Stapel in der Xcode-Quelle. Sehr doppelt. Wir haben versucht, die Demontage zu betrachten, konnten aber nicht viel daraus machen.
Noch einmal - es sieht so aus, als ob dies immer ein Ergebnis von shared_count ist, dem es anscheinend gehört der shared_ptr, der thread_info besitzt, erreicht zu früh Null.
Update: Es scheint, dass es möglich ist, in Situationen zu gelangen, die die obige Falle erreichen, ohne dass die Situation Schaden anrichtet. Seit der Behebung des Problems (siehe Antwort) habe ich gesehen, dass es passiert, aber immer nachdem thread_info- & gt; run () die Ausführung beendet hat. Verstehe noch nicht wie ... aber es funktioniert.
Einige zusätzliche Informationen:
Ich sollte beachten, dass die boost.sh von Pete Goodliffe (und von anderen modifiziert), die häufig verwendet wird, um Boost für IOS zu kompilieren hat den folgenden Hinweis in der Kopfzeile:
%Vor%Ich benutze diese Flags, aber ohne Erfolg.
Ich fand Folgendes, was sehr verlockend ist - es sieht so aus, als hätten sie das gleiche Problem in std::thread:
Das hat den Anschein, eine alternative Implementierung innerhalb von Boost für Arm-Prozessoren zu verwenden, die dieses Problem auch direkt anzugehen scheint:
spinlock_gcc_arm.hpp
Die in Boost 1.48 enthaltene Version verwendet eine veraltete Armbaugruppe. Ich habe die aktualisierte Version von Boost 1.52 genommen, aber ich habe Probleme, es zu kompilieren. Ich erhalte den folgenden Fehler: Vorhergesagte Anweisungen müssen sich im IT-Block befinden
Ich habe einen Hinweis auf eine ähnliche Verwendung dieser Anweisung gefunden: Ссылка
Ich konnte die gleiche Idee verwenden, um den 1.52-Code durch Ändern zu kompilieren der Code wie folgt (Ich habe eine entsprechende IT-Anweisung eingefügt)
%Vor%Aber auf jeden Fall gibt es ifdefs in dieser Datei, die nach der Arm-Architektur suchen, die in meiner Umgebung nicht so definiert ist. Nachdem ich die Datei einfach so bearbeitet habe, dass nur noch ARM 7 Code wurde verlassen, beschwert sich der Compiler über die Definition von BOOST_SP_ARM_BARRIER:
In der Datei enthalten von ./boost/smart_ptr/detail/spinlock.hpp:35: ./boost/smart_ptr/detail/spinlock_gcc_arm.hpp:39:13: error: Anweisung erfordert eine CPU-Funktion, die momentan nicht aktiviert ist BOOST_SP_ARM_BARRIER: ^ ./boost/smart_ptr/detail/spinlock_gcc_arm.hpp:13:32: Hinweis: Erweiterung von Makro 'BOOST_SP_ARM_BARRIER'
%Vor%Irgendwelche Ideen ??
Ich habe das herausgefunden. Es stellt sich heraus, dass das boost.sh-Skript, das ich in der Frage erwähne, das falsche Boost-Flag gewählt hat, um dieses Problem anzugehen - anstelle von BOOST_SP_USE_PTHREADS
(und dem anderen Flag dort, BOOST_AC_USE_PTHREADS
) stellt sich heraus, was benötigt wird auf IOS ist BOOST_SP_USE_SPINLOCK
. Dies ergibt letztlich die identische Lösung, die in dem std :: thread-Problem verwendet wird, auf das in der Frage Bezug genommen wird.
Wenn Sie für irgendein modernes IOS-Gerät kompilieren, das ARM 7 verwendet, aber einen älteren Boost verwendet (wir verwenden 1.48), müssen Sie die Datei spinlock_gcc_arm.hpp von einem neueren Boost (wie 1.52) kopieren. Diese Datei ist # ifdef für die verschiedenen Armarchitekturen, aber es ist mir nicht klar, dass die Definitionen, nach denen sie sucht, in der IOS-Kompilierumgebung unter Verwendung des Skripts definiert sind. Sie können also entweder die Datei bearbeiten (gewalttätig, aber effektiv) oder etwas Zeit investieren, um herauszufinden, wie Sie das ordentlich machen und korrigieren können.
In jedem Fall müssen Sie möglicherweise die zusätzliche Assembly-Anweisung, die ich oben in der Frage ausgeführt habe, einfügen: "Es ist ne; \ n" Ich bin noch nicht zurückgegangen, um zu sehen, ob ich das jetzt löschen kann, dass ich meine Kompilierungsumgebung funktionierendes Problem habe.
Aber wir sind noch nicht fertig. Der Code, der in Boost für diese Option verwendet wird, enthält, wie besprochen, Anweisungen für die ARM-Assemblersprache. Die ARM-Chips unterstützen zwei Befehlssätze, die in einem bestimmten Modul nicht gemischt werden können (der Bereich ist nicht sicher, aber offensichtlich ist Datei für Datei eine akzeptable Granularität beim Kompilieren). Die Anweisungen, die in Boost für dieses Sperren verwendet werden, enthalten Nicht-Thumb-Anweisungen, aber IOS verwendet standardmäßig den Thumb-Befehlssatz. Der Boost-Code, der das Problem mit dem Befehlssatz erkennt, prüft, ob arm aktiviert ist, aber nicht thumb , aber standardmäßig in IOS thumb ist an.
Es hängt davon ab, welchen Compiler Sie in IOS verwenden - den LLVM- oder LLVM-GCC von Apple. GCC ist veraltet und Apples LLVM ist die Standardeinstellung, wenn Sie XCode verwenden.
Für das Standard-Clang + Apple LLVM 4.1 müssen Sie mit dem Flag -mno-thumb kompilieren. Auch alle Dateien in Ihrer IOS-App, die einen Teil des Boosts verwenden, der Smartpointer verwendet, müssen ebenfalls mit -mno-thumb kompiliert werden.
Um Boost so zu kompilieren, denke ich, dass Sie einfach -mno-thumb zu den EXTRA_CPP_FLAGS im Skript hinzufügen können. (Ich habe das user-config.jam direkt beim Experimentieren geändert und bin noch nicht zum Aufräumen zurückgekehrt.)
Für Ihre App müssen Sie in Xcode Ihr Ziel auswählen, dann auf die Registerkarte "Build Phases" gehen und dort "Compile sources" auswählen. Dort haben Sie die Möglichkeit, Compilier-Flags hinzuzufügen. Fügen Sie für jede relevante Datei (einschließlich Boost) das Flag -mno-thumb hinzu. Sie können dies direkt in project.pbxproj auch tun, wo jede Datei
hat %Vor%ändern Sie das einfach zu
%Vor%Aber es gibt ein bisschen mehr. Sie müssen auch die Datei darwin.jam im Verzeichnis tools / build / v2 / tools ändern. In Boost 1.48 gibt es einen Code, der sagt:
%Vor%Dies muss zu
geändert werden %Vor% Abschließend sollten Sie im Skript boost.sh in der Funktion writeBjamUserConfig()
die Verweise auf -arch armv6 entfernen.
Wenn jemand weiß, wie man das etwas allgemeiner und sauberer macht, bin ich mir sicher, dass wir alle davon profitieren würden. Für jetzt ist das, wo ich hingekommen bin, und ich hoffe, dass dies anderen IOS Boost Thread-Benutzern helfen wird. Ich hoffe, dass die verschiedenen Varianten des boost.sh IOS Skripts aktualisiert werden. Ich werde später noch einige Links zu dieser Antwort hinzufügen.
Update: Für einen großartigen Artikel, der das Problem auf der Prozessor-Ebene beschreibt,
siehe hier:
Ссылка
Viel Spaß!
Ich benutze boost.asio, boost.thread, boost.smart_ptr usw. auf der iOS-Plattform, die App stürzt immer ab, wenn sie im Freigabemodus ausgeführt wird, was das Signal sigabrt auslöst. Der Crash-Aufruf-Stack lautet:
%Vor%Beim Versuch, das Problem zu lösen, habe ich die folgenden Artikel gefunden:
%Vor% Dann versuche ich -mno-thumb
zu meinem Projekt-Kompilier-Flag hinzuzufügen, und das Problem, das im Release-Modus aufgetreten ist, ist weg.
Ein neuer Fehler bringt jedoch heraus: EXC_ARM_DA_ALIGN , der bei dem Versuch, Netzwerkdaten in Host-Endian zu konvertieren, abgestürzt ist.
Wie in diesem Artikel [4] erwähnt, sind die ARM Anweisungen strikt, dass die Speicherdaten ausgerichtet werden müssen.
Und folge dem Artikel [Exc_arm_da_align][5]
, ich repariere es mit memcpy
für die Datenkonvertierung, anstatt direkt vom Zeiger zu konvertieren.
Tags und Links c++ multithreading ios boost