Zugriffsfehler auf "std::map" in " _Orphan_ptr(const _Nodeptr _Ptr)"
-
Ok, erstmal, wenn du mit erase die Maps selbst leeren willst, weil du unter umständen einen Eintrag (noch) nicht löschen möchtest, das ginge auch mit einer Schleife ohne goto
//map m auto iter = m.begin(); while(iter != m.end()) { if(/*erase case*/) { m.erase(iter->first); iter = m.begin(); } else { //what ever } }
Du darft
DeleteCriticalSection
erst aufrufen, wenn die CriticalSection nicht mehr benötigt wird. Also, auch, wenn kein Thread die mehr benötigt.
Wenn du auf mehrere Threads verteilt gemeinsam benötigte Ressourcen hast, muss du erst dafür sorgen, dass diese die Ressourcen nicht mehr benötigen, also warten bis die Threads alles soweit abgearbeitet haben, oder beendet worden sind.Was ist denn der Rückgabewert von
WaitForSingleObject
? Und schickst du das Signal auch wirklich am Ende des Threads?
-
@Schlangenmensch sagte in Zugriffsfehler auf "std::map" in " _Orphan_ptr(const _Nodeptr _Ptr)":
Ok, erstmal, wenn du mit erase die Maps selbst leeren willst, weil du unter umständen einen Eintrag (noch) nicht löschen möchtest, das ginge auch mit einer Schleife ohne goto
//map m auto iter = m.begin(); while(iter != m.end()) { if(/*erase case*/) { m.erase(iter->first); iter = m.begin(); } else { //what ever } }
Mit C++11 liefert
std::map::erase()
einen iterator auf das nächste Element oder aufstd::map::end()
-
@Schlangenmensch
Vielen Dank für den Code-Schnipsel. Is wesentlich besser als meiner!Das "WaitForSingleObject" gibt "0" zurück.
Es wird sogar (versehentlich) zweimal durchlaufen.
Beim ersten Mal sieht man auch die TRACES, die das Thread-Ende anzeigen.
Und man kann die Zeit ablesen die zum Durchlaufen des "WaitFor.." gebraucht wurde.
Beim zweiten Mal gibts dann keine Zeitdifferenz. Thread ist ja weg.
Sieht also so aus, als würde es funktionieren.@firefly Und ja, ich verwende noch C++11. Bin wohl in der falschen Doku gelandet.
... Oh nee, doch nicht. Bei Key-basiertem "erase()" wird ein "size_type" zurückgegeben.
Aber davon abgesehen:
Es kommen ja zwei "erase()" hintereinander.
Und es kracht erst beim zweiten ("Rsp"-map), wenns da durch geht.
Durch die "if"-Abfrage ist ja gewährleistet, dass in beiden "maps" was drin steht.Ansonsten krachts immernoch, wenn die maps leer sind, und das auch immer bei der "..Rsp"-map.
-
Hmm dann wird es wohl ohne Beispiel code, welcher das Problem nachstellt, schwer dir zu helfen
-
@firefly Huch, danke. Hätte ich noch mal nachlesen sollen, hab ich so nämlich noch nicht wirklich gebraucht.
Aber, den nächsten Iterator gibt es nur, wenn man erase den Iterator übergibt, ich habe ja geschlafen und den Key übergeben, dann wird die Anzahl gelöschter Elemente zurück gegeben, wie @elmut19 richtig angemerkt hat.
@elmut19 wenn nix hilft, dann alles an Code entfernen, dass nicht mit dem Problem zu tun hat und langsam einem Minimalbeispiel annähern. Zwischendurch immer mal überprüfen ob das Problem noch besteht. Dann kommst du vlt auch zu einem Beispiel, dass du hier teilen kannst.
-
@Schlangenmensch
Jedenfalls vielen vielen Dank an Euch alle.
Mal sehn, was mir noch an möglichen Änderungen einfällt.
Ich werds dann hier reinschreiben.
Vielleicht stimmt was nicht mit der Zugriffshierarchie auf die Objektkette.
Grundsätzlich muss das ja funktionieren.Hab versucht, den CppCheck zu installieren (Version für VS 2022).
Der mag mein VS2019 nicht. Ausgewiesenes Release für VS2019 hab ich nicht gefunden.
Cppcheck hinterlässt schon mal einen sehr schlechten Eindruck --> gestorben!Habe gerade auch festgestellt, dass sich die Elemente der "Rsp"-map nur innerhalb des Threads löschen lassen, wo ich sie reingeschrieben habe.
Selbst in dem Thread, der die einzelnen ServerThreads erzeugt, kann ich da kein Element löschen --> selber Fehler ("_Orphan...").
Für die "RW"-map funktioniert das aber und zwar bis zum Destruktor der "BaseAnlage" hinunter.
Die Inhalte beider maps sind Member derselben Klasse (Basis-Klasse, "CMrSocketThread"). Die "maps" sind Member der "BaseAnlage" und als Verweis (m_pmapSocketThreadRsps) in der Unterklassen von CMrSocketThread.
Von dieser Basis-Klasse sind der TCP-ClientThread und die TCP-ServerThreads abgeleitet, respektive natürlich die Klassen,
über die diese Threads verwaltet (Start(), Stop(), ..) werden.
Die Ringspeicher im Inhalt der "Rsp"-map werden auch irgendwie noch initialisiert und auch individuell erzeugt.
Aber ich kann diesen Inhalt, als "RspMap->second->Ringspeicher.irgendwas()" überall,
innerhalb meines "Anlage"-Objekts bearbeiten und auch "delete" drauf ausführen.
Aber ich kann an selber Stelle kein "erase()" auf dieses map-Element ausführen.
Daher meine Annahme, dass es sich um eine spezielle Eigenschaft der "std::map" handelt, die hier versagt.Das mit dem "erase()" am geeigneten Ort, lässt sich ja hinbekommen.
Aber das beim Beenden meiner Anwendung, selbst wenn die "map" leer ist, ist schon zum Verzweifeln.
-
Habe es inzwischen mit einer eigenen Linked List probiert.
Hier gibts leider ähnliche Fehler.
Ein "delete" auf ein Element ergibt Heap-Fehler. (Habs auch mit "delete[]" probiert.)
Und wenn ich auf die "deletes" verzichte (Ich mache ja jeweils ein explizites "delete" auf jeden einzelnen dieser Ringspeicher, welches auch funktioniert, jedenfalls ohne Absturz!),
so kann ich zwar die debug-Version beenden, die Release-Version bleibt aber hängen.// Ich verwende nun eigene Linked List! "itThreadRsps" ist Element dieser Linked List delete itThreadRsps->pMrThreadRsp->pWriteRsp; // keine Probleme delete itThreadRsps->pMrThreadRsp; // Heap-Fehler, wenn auskommentiert -> Deadlock beim Beenden // Wenn ich das Eine mache, muss ich natürlich das Andere jeweils auskommentieren, // da das Erste ja im Zweiten enthalten ist.
Es scheint wohl an diesem ominösen Ringspeicher zu liegen,
den mein Vorgänger geschrieben hat und in dem ich mich leider
überhaupt nicht auskenne. Bisher hat der ja, ohne "map", etc. funktioniert.
-
@elmut19 sagte in Zugriffsfehler auf "std::map" in " _Orphan_ptr(const _Nodeptr _Ptr)":
Habe es inzwischen mit einer eigenen Linked List probiert.
Hier gibts leider ähnliche Fehler.Wer hätte das gedacht! (sorry, klingt jetzt blöd, aber dir wurde gesagt, dass es nicht dem Container
std::map
liegt)
-
@elmut19 Für mich sieht einfach nach wie vor so aus, als ob dir die manuelle Speicherverwaltung um die Ohren fliegt. Kombiniert mit Multithreading ein großer Spaß.
Da wir deinen Ringspeicher überhaupt nicht kennen, können wir nichts dazu sagen. Vlt ist ein Fehler in dem Ringspeicher, oder du benutzt den anders, als dein Vorgänger das vorgesehen hat?
-
@elmut19 sagte in Zugriffsfehler auf "std::map" in " _Orphan_ptr(const _Nodeptr _Ptr)":
Ein "delete" auf ein Element ergibt Heap-Fehler. (Habs auch mit "delete[]" probiert.)
Und wenn ich auf die "deletes" verzichte (Ich mache ja jeweils ein explizites "delete" auf jeden einzelnen dieser Ringspeicher, welches auch funktioniert, jedenfalls ohne Absturz!),Und wenn ich auf die "deletes" verzichte
Mal eine Frage: Hast du das
delete
also auskommentiert, nutzt aber trotzdem nochnew
?
-
@Schlangenmensch sagte in Zugriffsfehler auf "std::map" in " _Orphan_ptr(const _Nodeptr _Ptr)":
Für mich sieht einfach nach wie vor so aus, als ob dir die manuelle Speicherverwaltung um die Ohren fliegt. Kombiniert mit Multithreading ein großer Spaß.
Den Verdacht habe ich auch. Manuelle Speicherverwaltung, übermäßige Zeigerverwendung, offene Architektur fliegen hier vermutlich um die Ohren.
-
@Quiche-Lorraine @Schlangenmensch @wob
Ich blick ja schon lange nix mehr.
Mit der "std::map" hatte ich eher weniger Probleme.
Kann gut sein, dass ich ins neue auch irgend einen Scheiss reingebaut habe, zusätzlich.
Aber das Problem scheint trotzdem ähnlich zu sein.Aber im Ringspeicher wird viel "alloc()", " HeapCreate()" und auch "HeapLock()" verwendet und natürlich auch wieder freigegeben.
Aber vielleicht verträgt sich das nicht mit den zusätzlichen, neuen "new()".Und wenn ich im Vorgänger-Programm nachsehe, dann wurde dieser RIngspeicher schon vor knapp 30 Jahren zusammengebastelt
und unverändert ins neue und jetzige Projekt (auch schon bald 20 Jahre alt) übernommen.
-
Hast du denn jetzt mal eine statische Codeanalyse gemacht?
-
@DocShoe
CppCheck lässt sich leider nicht installieren.
Es gibt unter dem Menü "Analysieren" in VS2019 den Punkt "Codeanalyse".
Der brachte keine Erkenntnis.In stackoverflow habe ich auch gelesen, dass man dieses "HeapZeugs" am Besten meidet.
Es wird ja ein wirklich separater Speicher allokiert.
-
@elmut19 sagte in Zugriffsfehler auf "std::map" in " _Orphan_ptr(const _Nodeptr _Ptr)":
In stackoverflow habe ich auch gelesen, dass man dieses "HeapZeugs" am Besten meidet.
Wie meinst du das? Du willst doch dynamisch Speicher allozieren. Wie würdest du das denn ohne Heap machen?
-
@Schlangenmensch sagte in Zugriffsfehler auf "std::map" in " _Orphan_ptr(const _Nodeptr _Ptr)":
@elmut19 sagte in Zugriffsfehler auf "std::map" in " _Orphan_ptr(const _Nodeptr _Ptr)":
In stackoverflow habe ich auch gelesen, dass man dieses "HeapZeugs" am Besten meidet.
Wie meinst du das? Du willst doch dynamisch Speicher allozieren. Wie würdest du das denn ohne Heap machen?
Er meint spezielle Heap-Funktionen aus der WinApi, die allokieren nochmal woanders als der Standard-C++ Heap.
-
@Tyrdal Ah, danke Ich nutze zu selten direkt die WinAPI und vergesse gerne das der Thread hier unter WinAPI liegt.
-
@elmut19 sagte in Zugriffsfehler auf "std::map" in " _Orphan_ptr(const _Nodeptr _Ptr)":
In stackoverflow habe ich auch gelesen, dass man dieses "HeapZeugs" am Besten meidet.
Es wird ja ein wirklich separater Speicher allokiert.Wieso das?
HeapAlloc/HeapFree
verhaltem sich das doch genauso wienew/delete
.
Du könnest damit anfangen, diese manuelle Speicherverwaltung in smart pointer zu verpacken. Dummerweise muss man beiHeapAlloc
einen Heap angeben, dessen Speicher man anfordert. Wenn in eurer Anwendung nur der Programmheap benutzt wird könnte man da so umsetzen (ungetestet):struct HeapDeleter { HeapDeleter() = default; // TO DO: // Member für Heap-Handle mitführen, falls ein anderer Heap als der ProcessHeap benutzt wird. void operator()( void* mem ) { ::HeapFree( ::GetProcessHeap(), 0, mem ); } }; void f() { DWORD const mem_size = 1024; std::shared_ptr<void> mem = std::shared_ptr<void>( ::HeapAlloc( ::GetProcessHeap(), 0, mem_size ), HeapDeleter() ); }
-
@DocShoe
Danke für die Idee mit dem Smartpointer. Ich muss mich damit befassen.
Vielleicht hilft das ja.
Ob ich den Ringspeicher derart umschreiben kann oder das schon auf das Objekt anwenden kann, in dem der Ringspeicher drin ist (Zusammenfassung meiner Übertragungsdaten), muss ich auch überlegen.
Ich sehe das Problem nun hauptsächlich hierin, dass die "std::map" innerhalb ihrer Verwaltung diesen externen Speicher sieht, den sie an besagter Stelle nicht mehr kennt.
Und dieser Ringspeicher ist/war für mich bisher einfach eine Blackbox.
Ich sehe auch wenig Möglichkeiten, das Ding umzuprogrammieren.
Aber es wäre auch noch eine Idee.
Vielleicht kann ich mit Smartpointer auch sowas wie einen Wrapper konstruieren, damit die "map" das gar nicht sieht.
-
Das Problem scheint zu sein, dass irgendwo Memory Corruption stattfinded, weil an allen möglichen Stellen Resourcen angefordert und freigegeben werden. Ein doppeltes delete/free/HeapFree an einer Stelle kann dazu führen, dass dir an einer anderen Stelle alles um die Ohren fliegt. Diesen Wildwuchs solltest du erstmal zähmen, und da sind smart pointer ein starkes Werkzeug. Wenn dann natürlich wieder rohe Zeiger durch die Gegend gereicht werden helfen dir auch smart pointer nicht weiter, musst mal gucken, ob das mit euren Schnittstellen funktioniert.
Ein Memory Profiler sollte das eigentlich erkennen, aber wenn du schon cppCheck nicht installieren kannst hast du vermutlich auch keinen Profiler.