Zugriffsfehler auf "std::map" in " _Orphan_ptr(const _Nodeptr _Ptr)"
-
@Tyrdal sagte in Zugriffsfehler auf "std::map" in " _Orphan_ptr(const _Nodeptr _Ptr)":
Klingt als hättest du dir irgendwo den Speicher "versaut".
Das vermute ich schon ein wenig länger, weiß aber nicht so recht wie ich es schreiben soll.
Ich probiere es mal.
Du nutzt meiner Meinung nach zu viele Pointer (z.B. pCRing, PMRDATA, PMRCANIDSRAM, std::map<CString,PMRCANIDSRAM>, std::map<CString,PMRDATA>* m_pmapData) und dadurch könnten die Verantwortlichkeiten nicht sauber definiert sein.
So könnte es z.B. sein das MRDATA::pWriteRsp an irgenteine Stelle gelöscht wird und es einen Destruktor für MRDATA gibt, welche pWriteRsp nochmals löschen will.
Aus meiner Sicht müsste man deswegen den Code aufräumen und die Verantwortlichkeiten in Klassen packen. Warum z.B. muss pWriteRsp von Hand gelöscht werden? Warum kann das nicht die Klasse CRing bzw. MRDATA tun bzw. verantwortlich dafür sein?
Such dir bitte mal jede Stelle wo du einen Pointer nutzt und stelle dir die folgenden Fragen?
- Handelt es um einen Zeiger, welcher Ressourcen allokiert?
- Wenn ja, wer ist für das Löschen verantwortlich? Wer für das Allokieren?
- Sind Zugriffe auf den Zeiger immer sicher?
- Welche Querabhängigkeiten entstehen durch die Verwendung des Zeigers?
- Kann man anstatt des Zeigers auch eine Kopie nutzen?
Schau dir noch mal
MRDATA::pWriteRsp
an. Durch die Verwendung eines Zeiger ist die Lebenszeit von pWriteRsp nicht unbedingt an die Lebenszeit der MRDATA Instanz gebunden. Du hast in der UML Sprache hier eine Relation. Würdest du gegegen beiMRDATA::pWriteRsp
keinen Zeiger nutzen, so wäre die Lebenszeit von pWriteRsp an die Lebenszeit der MRDATA Instanz gebunden. Du hättest in der UML Sprache eine Aggregation. Ähnliches gilt fürstd::map<CString,PMRDATA> m_mapData;
.
-
@Quiche-Lorraine
Ja. Ich halte die stl auch für genial!
Halte deshalb auch schon seit fünf Wochen an dem Konzept fest.
Habe auch schon an alle möglichen Stellen gedacht, wo noch mein Pointer manipuliert werden kann.Ich habe das Ganze schon soweit manipuliert, dass ich in der "map" nur noch einen "NULL-Pointer" habe und meinen bisherigen Pointer für die Operationen verwende.
Von der "map" brauche ich dann nur den Key, damit ich weiss wer nach den Daten fragt. Und ich habe sichergestellt, dass auch nur der eine Kandidat mit dem "NULL-Pointer" etwas in die "map" geschrieben hat."zu viele Pointer (z.B. pCRing, PMRDATA, PMRCANIDSRAM, st"
Hierfür sorry. PMRDATA ist identisch mit PMRCANIDSRAM.
Ich hab es anfangs im Text nur umbenannt. In Fehlerausgabe ist das Original.
Es ist der Datentyp der "struct", die als Element in der "map" ist.
Und "pCRing" ist Datentyp von drei gleichartigen Elementen in dieser "struct"Diese "struct" ist das zentrale Kommunikations-Objekt,
über das das HMI über den TCP-Client-Thread mit der Anlage kommuniziert.
Die "map" vervielfacht diese "struct", damit die Daten auf mehrere HMI´s verteilt werden können.
Das war auch die Idee zu dem gewünschten Feature, aus einer einzigen Client-App einen Verteiler zu basteln,
über den die Anlage nur noch eine TCP-Verbindung für mehrere Clients halten muss.
Genaugenommen ist das schon die einzige Änderung.
Soweit habe ich zumindest alles reduziert. Also sogar ohne zusätzliche Clients.Damit sollte doch eigentlich alles was ausserhalb noch so allokiert wird ausgeschlossen sein.
An das rechtzeitige Beenden der Threads, einschliesslich Aufräumen der Objekte habe ich auch gedacht.
Und ja, normalerweise wird auch allokiert (CRing).Aus der "struct" eine "class" zu machen, habe ich auch schon gedacht und damit angefangen.
Hat nicht auf Anhieb geklappt. Hängt viel anderes Zeug mit dran.
Wäre evtl. wieder einen Versuch wert.
-
@elmut19 sagte in Zugriffsfehler auf "std::map" in " _Orphan_ptr(const _Nodeptr _Ptr)":
Hierfür sorry. PMRDATA ist identisch mit PMRCANIDSRAM.
Das P... ist doch ein Windows spezifischer Präfix für einen Pointer. Deswegen mein Hinweis und die Frage: Funktioniert nicht hier auch ein MRDATA bzw. MRCANIDSRAM.
Versuche mal bitte das Problem dahinter zu verstehen. Wenn man Zeiger nutzt, so kann dies unerwartete Seiteneffekte haben, weil da eben eine Relation ist.
Genau deswegen gefallen mir Klassen. Man kann diese so entwickeln das sie Problem kapseln, einfach zu benutzen und schwer falsch zu benutzen sind.
Deswegen wäre mein erster Schritt MRDATA folgendermaßen uumzubauen
class MRDATA_2 private: public: bool bInUse; CRing ReadRsp; CRing WriteRsp; CRing ErrorRsp; long lWritePos; DWORD lWriteRspPos; bool bWriteToCan; bool bDataInWRITE; HANDLE hTimerThreadRspSleep; CRITICAL_SECTION m_csRspCriticalSection; // evt. C++ Äqauivalent };
Ein MRDATA besteht so ReadRsp, WriteRsp und ErrorRsp Ringpuffer,...
Ferner würde CRing sich eigenständig um die Ressourcenverwaltung kümmern. Ich habe hierzu mal ein std::array benutzt als ich ein Ringpuffer-Template geschrieben habe.
Und dann versuche doch mal einen Fehler in MRDATA_2 zu verursachen und danach mit MRDATA.
-
@Quiche-Lorraine
Hallo Quiche-Lorrain,
Vielen Dank noch für den Hinweis.
Aber hier auch ja, ich habe es probiert. Vielleicht habe ich nicht alle Optionen
mit dieser Variante durchgespielt, aber es endete mit dem gleichen Fehler.
Ich sehe es aber weiterhin noch als Option, da nochmal dran zu arbeiten.Ich bin aber momentan noch bei der Variante, die "struct" in eine "echte" Klasse umzubauen.
Bisher habe ich nur mal das "struct" gegen "class" getauscht, ohne irgendwelche Konstruktoren oder Destruktoren einzubauen.
Vielleicht verliert der Compiler durch das "struct" den Bezug zu internen
Destruktoren der Elemente und vermutet daher dort vergessenen Objekte,
weshalb dann der Fehler ausgelöst wird.
-
Nein, ein
struct X
ist nichts anderes alsclass X { public: // ... }
(also
public
als Standardzugriffsmodifizierer - als auch beim Ableiten, aber das nutzt du ja nicht).
Du kannst dort ebenfalls Konstruktoren, Destruktoren sowie Memberfunktionen implementieren.Mit "Umbau zur Klasse" ist nur gemeint, daß du nicht nur eine reine Datenstruktur hast, welche von außen manipuliert wird, sondern auch Memberfunktionen, welche sich um den internen Zustand kümmern (Validierung, De-/Allokationen, ...).
Und deine Problembeschreibung im Eingangsbeitrag deutet wirklich darauf hin, daß der Speicher der Anlage-Klasse irgendwie überschrieben wurde, so daß die
map
-Objekte falsche Zeiger beinhalten. Gerade das Crashen auch bei einem leerenmap
zeigt ja, daß es nicht an den enthaltenen Daten liegen kann.
Verschieb doch mal diesemap
-Objekte an den Anfang oder Ende deiner Anlage-Klasse (ich nehme mal an, du hast noch mehr als diese zwei Member).Oder zeige mal die Member der Anlage-Klasse, sowie dessen Destruktor.
PS: Du kannst es auch mal mit einem Datenhaltepunkt (data breakpoint) auf das
map
-Objekt versuchen, um Schreibänderungen zu finden: Verwenden von Breakpoints im Visual Studio-Debugger: Festlegen von Datenbreakpoints (nur nativer C++-Code)
-
Ich kann mich da nur wiederholen:
- mach eine statische Codeanalyse, zB mit cppCheck, um Fehler im Programm zu finden
- benutz einen Profiler, um ungültige Schreibzugriffe in Speicher zu finden.
Undefined Behaviour zu finden und zu beseitigen ist so das Unangenehmste, was man machen muss.
-
@DocShoe sagte in Zugriffsfehler auf "std::map" in " _Orphan_ptr(const _Nodeptr _Ptr)":
@It0101 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)":
Ich werd wohl ne eigene "map" schreiben müssen.
Bei uns im Unternehmen gab es in der pre-C++11-Zeit auch viele selbstimplementierte Container, aber das war alles fürchterlich. Ich habe dann nach und nach nachgewiesen, dass die Performance der STL erheblich besser ist und die Usability auch. Seitdem kam keiner mehr auf die Idee sowas selber zu schreiben.
Da habe ich ein Deja-Vue. An Teil 1 arbeite ich noch (also Überzeugung, nicht eigene Container), aber den Mythos "std::vector ist langsam" und "std::vector" ist für viele Elemente nicht geeignet" hält sich hartnäckig :(.
Ich habe solche Diskussionen immer damit erstickt:
https://i.stack.imgur.com/G70oT.pngManch einer verwendet nachwievor den falschen Container für den falschen Anwendungsfall.
-
@Quiche-Lorraine sagte in [Zugriffsfehler auf "std::map" in " _Orphan_ptr(const _Nodeptr _Ptr)"]
Genau deswegen gefallen mir Klassen. Man kann diese so entwickeln das sie Problem kapseln, einfach zu benutzen und schwer falsch zu benutzen sind.
Insbesondere, wenn man ihre Kopierfähigkeit/Bewegungsfähigkeit einschränkt. Auf die Art hab ich schon so manches Ei gefunden, weil manche Dinge dann unerwartet doch irgendwie kopiert wurden.
-
@Th69 sagte in Zugriffsfehler auf "std::map" in " _Orphan_ptr(const _Nodeptr _Ptr)":
Mit "Umbau zur Klasse" ist nur gemeint, daß du nicht nur eine reine Datenstruktur hast, welche von außen manipuliert wird, sondern auch Memberfunktionen, welche sich um den internen Zustand kümmern (Validierung, De-/Allokationen, ...).
Genau.
Denn mit einer gut designten Klasse reduziert man einiges an Code-Komplexität.
Und das versuche ich @elmut19 zu erklären. Viel C Code ist offener Natur und funktioniert nur deswegen gut, weil man sich sehr diszipliniert an Regeln hält.
Mit C++ wird das wesentlich einfacher, da man dank RAII/STL sich fast nicht mehr um Ressourcenverwaltung kümmern muss und dank den Klassen Kapselungen besser implementieren kann.
So richtig verstanden habe ich dies aber erst, als ich jede Menge C Code nach C++ portierte.
PS:
@elmut19Warum nicht so?
// Democode, nicht lauffähig class MRDATA_2 private: bool bInUse; CRing ReadRsp; CRing WriteRsp; CRing ErrorRsp; long lWritePos; DWORD lWriteRspPos; bool bWriteToCan; bool bDataInWRITE; HANDLE hTimerThreadRspSleep; CRITICAL_SECTION m_csRspCriticalSection; // evt. C++ Äqauivalent public: void GetReadRsp(CRing& ReadResponse) { // EnterCriticalSection // ReadResponse = this.ReadRsp // LeaveCriticalSection } // ... };
Deine ganzen Daten sind private. Du kommst also außerhalb der Klasse nicht mehr an deine Daten ran. Also musst du z.B. die Funktion
GetReadRsp()
nutzen und diese nutzt automatisch deineCRITICAL_SECTION
Instanz. Sofern deine Klasse korrekt implementiert ist, zwingst du dich also automatisch zur Thread Safety.
-
@Quiche-Lorraine
Vielen Dank nochmal für Eure Vorschläge.
Ich brauch nun eine Weile, um mir das alles nochmal durch den Kopf gehen zu lassen.
Ich werd mal mit einer vollständigen Klasse statt der "struct" (bzw. einfach nur "class" zu schreiben) weitermachen.
Und dann noch die Sache ohne Pointer. Davon hab ich schon ne Version als "struct".
Das ganze Anlage-Objekt ist wirklich ein Mega-Teil und kaum zu überblicken.
Vorerst halte ich noch Abstand, das hier abzudrucken.
Habe zudem noch ein ganz anders Problem reinbekommen, um das ich mich auch noch kümmern muss
-
Der Fehler liegt nicht an der
MRDATA
-Datenstruktur!
Das ganze sollte doch mit ein paar Minuten Debugging gelöst sein...Oder generell, wie schon von @DocShoe vorgeschlagen, CppCheck benutzen - für VS das passende CppCheck Add-In.
-
Mal ne blöde Frage, hältst du irgendwo Iteratoren auf Map Elemente und durch eine
erase
oder so ist die Position nicht mehr dereferenzierbar? Sowas ist mir vor nicht all zu langer Zeit mal passiert.
-
@Schlangenmensch
Hallo Schlangenmensch,
das ist mir zwischendurch natürlich auch passiert.
Da stürzt es natürlich gleich ab. Gibt dann ne andere Fehlermeldung.
Habe diverse Sachen eingebaut, um sicherzustellen, dass auch der jeweilige Thread weg ist, bevor das map-Element gelöscht wird.
Ich setze die Iteratoren möglichst auf "end()", wenn ich sie nicht mehr brauche.
Das Programm läuft auch schon mal übers Wochenende und sammelt dabei Daten.
Auch kann ich Verbindungen Trennen und wieder aktivieren, wobei natürlich die zugehörigen Threads auch eliminiert werden.
Also für die Dauer des Betriebs habe ich das alles ja hinbekommen,
abgesehen,
wenns bei diversen anderen Versuchen dann da auch gekracht hat.
Nur, wenns beim beenden des Programms aus dem Destruktor des Basis-Objekts raus geht, dann krachts immer.
Daher denke ich, dass die Destruktoren nochmals alle aufgerufen werden
und es in der "map" eben stecken bleibt, weil die Aufruf-Schlange durch die "struct" unterbrochen wird.
@Th69 Ja, die Datenstruktur ("struct") funktioniert ja schon lange.
Es ist die "map" drum rum, die versagt. Aus der "struct" wird auch irgendwie der HMI Teil angesprochen ("irgendwie", ja stammt noch vom Vorgänger).
Ich sehe daher auch meine Umbaumöglichkeiten eingeschränkt.
@DocShoe Den cppCheck hatte ich auch schon mehrfach angedacht, bin aber bisher immer im Versuch stecken geblieben, weils dann anders auch ging.
-
Rufst du etwa irgendwo (aus dem anderen Thread heraus) explizit
delete
für diesemap
auf?
Oder meinst du nurmap.clear()
, wenn du von..., dass auch der jeweilige Thread weg ist, bevor das map-Element gelöscht wird.
bzw. aus deinem Eingangsbeitrag
Innerhalb des Threads, der die Daten in die "std::map" geschrieben hat,
kann das map-Element auch wieder gelöscht werden, sowie auch die Daten darin bereinigt werden können.schreibst?
Ansonsten mußt du uns wirklich mal den Code der betreffenden Stellen zeigen.
-
@Th69
Ich versuche sogar alles.
In erster Linie bereinige ich die "map"-Elemente in dem Thread, in dem ich sie reingeschrieben habe, genauer das eine Element, das dieser Thread geschrieben hat.
Da benutze ich auch das "delete()" auf die "Objekte" (Ringspeicher) innerhalb der "map".
In den Objekten, die ihren Thread aufrufen (zu jedem Thread gehört eins für die "open()" und "close()" Methoden z.B.), warte ich, bis explizit der Thread über ein Flag sein Ende angezeigt hat, bis ich das auch beende, versuche aber auch zusätzlich zu bereinigen.
An solchen und auch anderen Stellen bin ich damit auch immer wieder auf die Nase gefallen, da auch diese Probleme ("_Orphan_ptr") auftraten und dann auch teils im Betrieb.
Da habe ich auch immer wieder zu viel des Guten versucht.Mein Basis-ClientThread, der die ganzen Nachrichten an die aufgeschalteten ServerThreads verteilt, ist natürlich drauf angewiesen,
dass sein Iterator auch immer auf Daten zeigt (Thread beendet und seine Daten aus "map" gelöscht).
Sollte aber eines dieser Elemente gelöscht worden sein, ohne dass dieser das rechtzeitig merkt,
dann steht dieser Iterator auf "end()". Der Crash zeigt dann aber auch einen anderen Grund. Und der ist dann eigentlich von der Ursache her trivial, also erklärbar.Aber am Ende des Anlage-Objekts kommt dann immer dieser "Orphan" Fehler.
Da gibt es dann auch zwei Möglichkeiten:- Die "maps" sind schon alle ordentlich bereinigt und leer.
Dann kommt die eine "Orphan" Methode. - Es ist noch ein Element drin, das ich im Destruktor des Anlage-Objekts, explizit und auch mit "delete()" auf die Ringspeicher, löschen möchte,
dann kommt im "erase()" eine andere "Orphan" Methode.
Also die Objekte in der "struct" (Ringspeicher) kann ich da sogar bereinigen.
Nur dann das "map"-Element mit "erase()" auch noch löschen, nein.
Habe schon alle Codefragmente hin und her geschoben.
Teils haben sie dort dann funktioniert, teils auch nicht. Dann wieder dort raus.
Nur das Programm beenden klappt nie!
Und da verabschiedet es sich auch nicht mit einer Fehlermeldung und ist dann weg.
In der Regel muss ich sogar den Taskmanager zuhilfe nehmen.
- Die "maps" sind schon alle ordentlich bereinigt und leer.
-
Du versteifst dich zu sehr auf die
map
und dessen Elemente.
Du hast (höchstwahrscheinlich!) aber einen Speicherüberschreiber, der den Speicher desmap
-Objekts in der Anlage-Klasse korrumpiert.Daher noch mal der dringende Rat: benutze
CppCheck
oder debugge per Datenhaltepunkt (so daß möglichst direkt das Programm beendet wird ohne Elemente in diemap
einzufügen oder zu löschen)!!!
-
@Th69
Mit dem cppCheck werd ich mich auf jeden Fall auseinandersetzen.
Andererseits habe ich die Anwendung auch schon so konfiguriert,
dass erst gar nichts mehr in die "map" geschrieben wird.
Also so, dass in die "map" einfach nur ein NULL-Pointer geschrieben wird, statt ein Pointer auf die "struct".
Von der "map" habe ich dann nur den Key verwendet, um sicherzustellen,
dass ich im gewünschten Bereich bin.
Für diesen Fall habe ich dann den ursprünglichen Pointer auf meine alte "struct" verwendet.
Zusätzlich habe ich ausgeschlossen, dass irgendwelche ServerThreads gestartet wurden.
Also alles, was jemals in diese eine "map" mit diesen Ringspeicher-Objekten geschrieben wurde, war dann dieser NULL-Pointer.
Die andere "map", die eigentlich die Verwaltung der ServerThreads übernimmt, blieb dabei völlig unberührt und leer.
Trotzdem hats beim beenden gekracht, also in der "map" mit den Ringspeicher-Objekten.Bin noch nicht dazugekommen, weiterzumachen, da gerade eine andere Software Probleme macht.
-
@elmut19 Ohne Code wird es mühselig.
Vielleicht steht das schon hier im Thread aber,
was ist denn der letzte Aufruf aus deinem Code bevor es kracht bzw. in CBaseAnlage Zeile 256? Das scheint ja der Aufruf zu sein, bei dem es kracht.
Vielleicht mal da nen Breakpoint rein setzen und gucken was da passiert (oder schon vorher passiert ist).Sehe ich das Richtig, dass du die Ringspeicher manuell verwaltest? Kann es da beim Beenden der Software zu einem Double Free kommen?
Möglicherweise kannst du den Code auf ein wirkliches Minimalbeispiel reduzieren? Alles löschen, was nicht direkt mit dem Problem zu tun hat. Ist bei größeren Projekten mühselig, aber wenn sonst nix geht, kann man so das Problem gut einkreisen.
-
@Schlangenmensch
Der Code ist momentan noch oft doppelt gemoppelt und ähnlich wie hier auch an anderer Stelle zu finden.
Die "maps" sind beide Member von "CBaseAnlage".
Ich stelle das Ende der "~CBaseAnlage()" dann mal hier rein.
Wenn eine funktionierende Variante mal da ist, kann ich auch aufräumen.Es tauchen hier, je nachdem, was in den Threads passiert, drei Probleme auf.
- Beide "maps" sind leer:
--> Es kracht bei Ausführung der letzten "}" von "~CBaseAnlage()" und immer in der "xxRsp"-map und mit "_Orphan.." - Die "m_mapSocketThreadRsps" hat noch gültige Elemente:
--> Es kracht beim "erase()", nicht beim "delete XX->second->pWriteRsp;"
Momentan kann ich leider keine definitive Aussage zur zweiten "map", "m_mapServerRWThreads" machen.
Die enthält nur triviale Objekte, wie "CString".
Ich glaube aber, die machte beim "erase()" auch diese Probleme und auch mit "_Orphan..".
Das wäre aber wichtig für weitere Schlüsse. Müsste dazu aber diese solo haben, und das ist schwierig.
Trotzdem könnte es daran liegen, dass die Elemente in einem Thread reingeschrieben wurden. - In den "maps" sind ungültige Objekte:
--> Wenn ein Thread "gekillt" wurde, konnte er sein "map"-Element nicht löschen.
Dann steht in jedem Parameter Müll drin und es geht noch mehr schief.
Aber "erase()" endet auch mit "_Orphan.."
Wenn ich den Grund wüsste, warum es bei leeren "maps" kracht, die auch mit absoluter Sicherheit keinen anderen
Speicher berührt haben, wäre schon sehr viel geholfen, bzw. das grundsätzliche Problem gelöst.int iHelp; CString csKey; std::map<CString,PMRCANIDSRAM>::iterator itThreadRsps; std::map<CString,PMRSOCKETSERVERTHREADALL>::iterator itRWThreads; _again1: TRACE(_T("~BaseAnlage ---------------------- vor #Prepare and erase() all RWThread# (size: %d) / ThreadRsp (size: %d) (if (itRWThreads not empty))\n"), m_mapServerRWThreads.size(), m_mapSocketThreadRsps.size()); for (itRWThreads = m_mapServerRWThreads.begin(); itRWThreads != m_mapServerRWThreads.end(); itRWThreads++) { csKey = itRWThreads->first; itRWThreads->second->m_psData->m_iThreadAktionSoll = SOCKETCLIENTAKTION_SOLL_ENDE; itThreadRsps = m_mapSocketThreadRsps.find(csKey); if ((itThreadRsps != m_mapSocketThreadRsps.end()) && (itThreadRsps->second->bInUse) && (itThreadRsps->second->bInUse >= 0) && (itThreadRsps->second->bInUse < 3)) {// 24.08.22: "bInUse<3" Erkennung ungültiger Objekte EnterCriticalSection(&itRWThreads->second->m_csSocketThreadCriticalSection); if ((!itRWThreads->second->m_bInUseSocketThread) && (itRWThreads->second->m_bInUseSocketThread >= 0) && (itRWThreads->second->m_bInUseSocketThread < 3)){ LeaveCriticalSection(&itRWThreads->second->m_csSocketThreadCriticalSection); DeleteCriticalSection(&itRWThreads->second->m_csSocketThreadCriticalSection); itThreadRsps->second->bInUse = FALSE; delete itRWThreads->second->m_psData->pInBuf; itRWThreads->second->m_psData->pInBuf = NULL; itRWThreads->second->m_bInUseSocketThread = FALSE; SetWaitableTimerSleep(itThreadRsps->second->hTimerThreadRspSleep, (LONGLONG)(0));// HP, 08.05.18: Veranlasst den Thread sofort weiterzulaufen. LeaveCriticalSection(&itThreadRsps->second->m_csRspCriticalSection); DeleteCriticalSection(&itThreadRsps->second->m_csRspCriticalSection); if (!itThreadRsps->second->bInUse) {// 10.08.22: ergänzt. Soll vorzeitiges Ende der Anlage verhindern (bis "ClientThread" fertig) itThreadRsps->second->bInUse = FALSE; if (itThreadRsps->second->pErrorRsp) delete itThreadRsps->second->pErrorRsp; if (itThreadRsps->second->pReadRsp) delete itThreadRsps->second->pReadRsp; if (itThreadRsps->second->pWriteRsp) delete itThreadRsps->second->pWriteRsp; itThreadRsps->second->pErrorRsp = NULL; itThreadRsps->second->pReadRsp = NULL; itThreadRsps->second->pWriteRsp = NULL; if (!itThreadRsps->second->bInUse) itThreadRsps->second->bDataInWRITE = FALSE; TRACE(_T("~BaseAnlage ---------------------- RWThread Nr: All ThreadRsp prepared for delete\n")); } else { DoWaitableTimerSleep0((LONGLONG)(-1000) * 200); // in 100 Nano-Sekunden --> "200" = 0,02 Sec. goto _again1; } itRWThreads = m_mapServerRWThreads.end(); TRACE(_T("~BaseAnlage ---------------------- RWThread Nr: before erase\n")); EnterCriticalSection(&m_csmapRWThreadsCriticalSection); iHelp = m_mapServerRWThreads.erase(csKey); LeaveCriticalSection(&m_csmapRWThreadsCriticalSection); EnterCriticalSection(&m_csmapThreadRspsCriticalSection); iHelp = m_mapSocketThreadRsps.erase(csKey); LeaveCriticalSection(&m_csmapThreadRspsCriticalSection); TRACE(_T("~BaseAnlage ---------------------- RWThread Nr: after erase\n")); itRWThreads = m_mapServerRWThreads.begin(); goto _again1; } else { LeaveCriticalSection(&itRWThreads->second->m_csSocketThreadCriticalSection); DoWaitableTimerSleep0((LONGLONG)(-1000) * 200); // in 100 Nano-Sekunden --> 0,02 Sec. goto _again1; } }// if ((itThreadRsps .. found }// for(itRWThreads) _again2: TRACE(_T("~BaseAnlage ---------------------- vor All ThreadRsp (size: %d) Data delete and NULL, no erase() (if (ThreadRsp not empty))\n"), m_mapSocketThreadRsps.size()); for (itThreadRsps = m_mapSocketThreadRsps.begin(); itThreadRsps != m_mapSocketThreadRsps.end(); itThreadRsps++) { if ((itThreadRsps->second->bInUse >= 0) && (itThreadRsps->second->bInUse < 3)) {// Hinweis, dass Inhalt auf ungültige Daten zeigt SetWaitableTimerSleep(itThreadRsps->second->hTimerThreadRspSleep, (LONGLONG)(0));// HP, 08.05.18: Veranlasst Thread sofort weiterzulaufen. LeaveCriticalSection(&itThreadRsps->second->m_csRspCriticalSection); DeleteCriticalSection(&itThreadRsps->second->m_csRspCriticalSection); if (!itThreadRsps->second->bInUse) {// 10.08.22: ergänzt. vorzeitiges Ende der Anlage verhindern (bis "ClientThread" fertig) itThreadRsps->second->bInUse = FALSE; if (itThreadRsps->second->pErrorRsp) delete itThreadRsps->second->pErrorRsp; if (itThreadRsps->second->pReadRsp) delete itThreadRsps->second->pReadRsp; if (itThreadRsps->second->pWriteRsp) delete itThreadRsps->second->pWriteRsp; itThreadRsps->second->pErrorRsp = NULL; itThreadRsps->second->pReadRsp = NULL; itThreadRsps->second->pWriteRsp = NULL; if (!itThreadRsps->second->bInUse) itThreadRsps->second->bDataInWRITE = FALSE; TRACE(_T("~BaseAnlage ---------------------- ThreadRsp Data set to NULL.\n")); } else { DoWaitableTimerSleep0((LONGLONG)(-1000) * 200); // in 100 Nano-Sekunden --> "200" = 0,02 Sec. goto _again2; } } } DeleteCriticalSection(&m_csSocketThreadsEndCriticalSection); DeleteCriticalSection(&m_csmapRWThreadsCriticalSection); DeleteCriticalSection(&m_csmapThreadRspsCriticalSection); /* if (m_mapSocketThreadRsps.size() > 0) m_mapSocketThreadRsps.clear(); if (m_mapServerRWThreads.size() > 0) m_mapServerRWThreads.clear();*/ }
- Beide "maps" sind leer:
-
@elmut19 Das ist das Ende von dem Destruktor? Mich wundert gerade, dass überhaupt was funktioniert.
Das ist zu viel Code, da fehlt Abstraktion und Kapselung und dann noch 2 GOTO Sprungmarken oO
Kann es z.B. passieren, dass
DeleteCriticalSection(&itThreadRsps->second->m_csRspCriticalSection);
aufgerufen wird und das hinterher aufgrund vongoto _again1;
nochmalLeaveCriticalSection
aufgerufen wird?Warum überhaupt
erase
? Die Map wird nach dem Destruktor doch eh aufgeräumt?Ich habe gerade erstmal gedacht, dass du immer einen Eintrag in der Map überspringst, macht du aber aufgrund des GOTO nicht, glaube ich.
Kann dein Struct was du in
m_mapServerRWThreads
hältst nicht seine eigenen Ressourcen verwalten?Es wirkt auch komisch, dass du erst die
CriticalSection
verlässt und aufräumst, und dann Speicher freigibst, auf den in der Zwischenzeit ja wieder ein anderer Thread zugreifen könnte, oder?