Ich habe die folgende "Erste-Chance-Ausnahme" -Meldung, die von einer DLL stammt, die ich geschrieben habe und die in einer ausführbaren Datei läuft, die ich nicht geschrieben habe. Das heißt, die DLL ist ein Plugin. Wenn diese Ausnahme zum ersten Mal ausgelöst wird, schlägt ein Versuch fehl, eine Shared Memory-Map-Datei zu öffnen. Wenn ich Ausnahmen der ersten Chance ignoriere und einfach laufe, friert die Anwendung schließlich ein oder stürzt ab.
%Vor%Nach einigen Stunden scheint es durch einen Codeblock verursacht worden zu sein, der endlos wiederholt wird, bis eine erwartete Ausnahmebedingung gelöscht wird. Es stellt sich heraus, dass, wenn es nie klar wird, und dann diese Exception schließlich in eine andere Low-Level-Exception-Bedingung und / oder in Heap-Korruption verwandelt wird. All dies ist nur in dem Bemühen, einen gemeinsamen Speicherbereich mit Boost :: Interprocess zu öffnen.
Die erste Sache, die Dinge verkompliziert, ist, dass auf meinem Visual C ++ 2008-basierten Projekt die erste boost::interprocess::interprocess_exception
-Erstwahrscheinlichkeits-Ausnahme nicht ausgelöst und als Speicherort identifiziert wird, weil der Visual C ++ 2008-Compiler den Komplex nicht finden konnte Boost-Flavor Vorlagen Code in Frage. Durch einzelnes Durchlaufen der Assembly-Sprachansicht habe ich jedoch den Code gefunden, der explodiert.
Die oberste Zeile meines eigenen Codes, an der alles anfängt, ist:
%Vor% Die obige Klasse managed_shared_memory
stammt von interprocess_fwd.hpp und ist ein Standardteil der Boost Shared Memory API / Header. Da es auf einer Vorlage basiert, erweitert sich das Obige zu einem etwa 2Kchars langen C ++ - Boost-Vorlagenausdruck, der vom Linker und vom Debugger auf unterschiedliche Länge gekürzt wird. Visual C ++ 2008 hat keine Quellcode-Debugging-Funktionen mehr, scheint es, wenn diese Grenzen im Spiel sind.
Zum Beispiel, wenn es explodiert, bekomme ich diesen Call-Stack:
%Vor%Im Stack-Dump oben werden keine tatsächlichen geschriebenen Quellfunktionen des Endbenutzers angezeigt.
Wie soll ich das debuggen? Zweitens, gibt es ein bekanntes Problem mit boost-interprocess, mit Visual C ++ 2008? Drittens, was ist der Boost-Code unten und warum muss er endlos loopen?
%Vor%Weitere Schichten runter, wir kommen zu:
%Vor%Wie auch immer, versuchen Sie nicht, dies zu Hause Kinder zu debuggen, hier ist was passiert:
Schließlich habe ich mit meiner Ninja-ähnlichen Fähigkeit, mehrere Millionen Zeilen Assemblersprache zu durchlaufen, die bösen Debugger-Einschränkungen von Visual C ++ 2008 besiegt und den fraglichen Code gefunden.
Dies ist, was tatsächlich explodiert: create_device<FileBased>(dev...
.
Etwas Kontext hier: managed_open_or_create_impl.h Zeile 351 ...
%Vor%Ich glaube, ich hatte einige der gleichen Probleme, die Sie haben. Sehen Sie sich die Funktion "shared_memory_object :: priv_open_or_create" in "\ boost \ interprocess \ shared_memory_object.hpp" an. An der Spitze dieser Funktion steht ein weiterer Funktionsaufruf "create_tmp_and_clean_old_and_get_filename", der eine Funktionskette startet, die das Löschen der Shared-Memory-Datei beendet. Ich habe diesen Funktionsaufruf in der priv_open_or_create-Funktion nach unten verschoben, wo die case-Anweisungen beginnen. Ich glaube, ich verwende Boost 1.48. Hier ist die endgültige Version der Funktion, die ich geändert habe:
%Vor%Übrigens, wenn irgendjemand die offiziellen Kanäle kennt, die ich durchlaufen kann, um dies zu verifizieren und zu Boost hinzuzufügen, lasst es mich wissen, weil ich es hasse, solche Sachen zu modifizieren, ohne die volle Wirkung zu kennen.
Hoffe, das hilft!
Boost ist voll von erstaunlichen und gruseligen Dingen.
Eine einfache Problemumgehung unter Windows könnte darin bestehen, zu managed_windows_shared_memory
anstelle von managed_shared_memory
zu wechseln, Sie können eine Vielzahl von unangenehmen Absturz- / Hang-Problemen lösen, und es scheint eine Art Crash / Hang-Problem zu verursachen durch die Unterschiede zwischen Windows-Dateisystem-Verhalten und Unix-Dateisystem Verhalten, und insbesondere scheint es, dass mit Boost und managed_shared_memory
unter Windows ist es möglich, mit Windows-Dateisystem Sperrbeschränkungen zu laufen. Ich bin informiert, dass eine Anstrengung, um damit fertig zu werden, in BOOST 1.53 abgeschlossen wurde, aber ich benutze Boost 1.53 und ich habe immer noch dieses Problem.
Mit regulärer managed_shared_memory
unter Windows erhalten Sie Persistenz über die Lebensdauer von Client- oder Serveranwendungen hinaus. Dies könnte in einigen Fällen wünschenswert sein, daher ist die Problemumgehung für diese Personen keine echte Lösung.
In meinem Fall brauchte ich das sowieso nicht, obwohl ich dachte, es wäre praktisch, es stellt sich heraus, dass es mehr Schmerz ist, als es wert ist, zumindest mit der aktuellen Boost-Implementierung unter Windows.
Ich möchte auch darauf hinweisen, dass das Löschen der gemeinsamen Speicherdatei die Hauptursache für die Race Condition zu sein scheint, die das Problem verursacht, das in der obigen Frage aufgetreten ist. Die richtige Synchronisierung beim Erstellen und Überprüfen und Löschen der Datei scheint für eine reale Implementierung des Systems wesentlich zu sein, und insbesondere scheint es ein verheerendes Problem zu sein, wenn Sie Ihren Master (Server) die Shared-Memory-Datei löschen lassen während einige Clients es noch verwenden. Ein Neustart erscheint notwendig, um das resultierende Lock + NTFS-Dateisystem-Chaos zu löschen.
Wenn ich eine echte Lösung finde, werde ich sie veröffentlichen, aber das obige ist mehr Informationen, als ich irgendwo anders finden könnte. Seien Sie vorsichtig bei managed_shared_memory
und erwägen Sie, managed_windows_shared_memory
zu verwenden und vergessen Sie zu versuchen, die "persistent shared memory" Idee zu aktivieren. Verwenden Sie stattdessen nicht persistente Fenster - nur managed_windows_shared_memory
.
Dies zu lösen, während die managed_shared_memory
-Klasse in meiner Anwendung beibehalten wird, bedeutet wahrscheinlich, dass alle Zugriffe auf das managed_shared_memory
-Objekt in einer weiteren Ebene von Interprozess-Synchronisations-Primitiven oder sogar mit einem rohen Win32-API-Mutex eingeschlossen werden. Boost könnte etwas Äquivalentes tun, würde aber wahrscheinlich noch mehr zufällige Komplexität einführen.
(Abgesehen davon: Bin ich der Einzige, der denkt, dass Template-All-the-Things in der heutigen Zeit zu weit verbreitet ist und besonders in Boost?)
Update 2: Ich habe eine alternative Möglichkeit gefunden, managed_shared_memory
einzufrieren, und das wiederum friert jede App ein, von der Sie es verwenden. Ich habe nicht erwartet, dass es so einfach ist, Deadlocks mit Boost zu erzeugen, aber es ist ziemlich einfach zu machen. Der Mutex-Code in der Implementierung wird für immer einfrieren und auf einen Mutex warten, den ein anderer Benutzer des verwalteten gemeinsamen Speichers ohne Freigabe freigegeben hat. Dieser endlose Schlaf, der auf einen Mutex wartet, der nie veröffentlicht wird, ist ein weiterer tiefer Designfehler in dieser Boost-Interprozess-Implementierung, die ich bis jetzt, zumindest unter Windows, einige ernsthafte Designfehler aufgezählt habe. Vielleicht funktioniert es wunderbar unter Linux.
Der Code, der dies anzeigt, ist die Methode find (), die wie folgt aufgerufen wird:
%Vor%Hier ist der Stack-Trace für einen Mutex-Deadlock (aka endlose Warte, eingefrorene Aufgabe):
Einzige Lösung, wenn Sie hierher kommen, ist das Löschen des freigegebenen Speicherbereichs, nachdem alle angehaltenen Prozesse gestoppt oder beendet wurden, die auf diesen Mutex warten.
%Vor%Tags und Links c++ boost visual-c++-2008 boost-interprocess