Threads und Heap Speicher
-
Hallo alle zusammen,
dies ist mein erster Post in diesem Forum und ich hoffe ihr könnt mir weiterhelfen. Normalerweise poste ich nicht so gerne in Foren sondern suche im Web nach Lösungen für mein Problem. Nach 3 Tagen suchen und langen rumprobieren komm ich aber absolut nicht weiter, deshalb dachte ich mir ich suche eine kompetentes Forum auf und hoffe, dass mir dort jemand weiter helfen kann.
Bei meinem Problem geht es um Threads unter Windows, welche mit Hilfe von "CreateThread" bzw. der CRT "_beginthreadex" erzeugt werden. Doch bevor ich mein Problem erkläre hier noch ein Code schnippsel:
thread1 = _beginthreadex(NULL, 0, ThreadFunction, NULL, 0, &thread1Id); /* ein paar Codezeilen später */ unsigned int WINAPI ThreadFunction(LPVOID param) { for(int i = 0; i < 20; i++) { char* pcLine = new char(); sprintf(pcLine, "Thread %i: counting %i\n", (int)param, i); delete(pcLine); pcLine = 0; } return 0; }
Wie in dem Beispiel zu sehen ist möchte ich einfach nur ein Thread ausführen, der ein Objekt im Heap erzeugt, dieses Objekt bearbeitet und dann wieder den Speicher frei gibt. Leider kommt es bei diesem Beispiel jedoch zu einem "corrupted heap" beim freigeben des Speichers. Jedoch hab ich keinen Ahnung warum. Soweit wie ich das verstanden habe hat jeder Prozess in Windows einen Heapbereich, welchen er sich mit all seinen Threads teilt. Ein Thread besitzt nur einen eigenen Stack und benutzt den Heap des Prozesses, in dem der Thread läuft. Wenn ich jetzt einen Pointer in dem Thread erzeuge wird die Pointervariable im Stack des Threads gespeichert. Diese Variable zeigt dann auf einen Speicherbereich im gemeinsamen Heap.
Also dachte ich mir zu erst "naja...hmm, vllt ist new() und delete() nicht Thread-safe und es kommt zu konflikten, da der MainTrhead den Heap verändert.". Dies ist aber anscheinend nicht der Fall, wenn man die Multithreaded CRT verwendet (wurde so in einigen Foren geschrieben). Ich habe auch schon probiert mit "HeapCreate()" einen privaten Heap für den Thread zu erstellen, um mögliche Konflikte mit dem MainTherad zu vermeiden. So habe ich den Heapspeicher über HeapAlloc() allociert und mit HeapFree() wieder frei gegeben, aber auch dort hatte er ein Problem beim freigeben. Als ich dann mir dachte "na gut, irgendwo muss der Übeltäter ja stecken" und einfach alle unwichtigen Zeilen auskommentierte hat es funktioniert. Das Beispiel von oben funktioniert z.b wenn man die "sprintf" funktion auskommentiert. Mit dieser Zeile kommt es beim delete() zu einem Fehler, ohne sie läuft er durch. Also dachte ich mir "ok, dann liegt es anscheinend an dieser sprintf() CRT Funktion". Nach einwenig gegoogle fand ich dann auch einen Hinweis in der MSDN:A thread in an executable that is linked to the static C run-time library (CRT) should use _beginthread and _endthread for thread management rather than CreateThread and ExitThread. Failure to do so results in small memory leaks when the thread calls ExitThread. Another work around is to link the executable to the CRT in a DLL instead of the static CRT. Note that this memory leak only occurs from a DLL if the DLL is linked to the static CRT and a thread calls the DisableThreadLibraryCalls function. Otherwise, it is safe to call CreateThread and ExitThread from a thread in a DLL that links to the static CRT.
(Quelle: http://msdn.microsoft.com/en-us/library/ms682659(VS.85).aspx)
Also habe ich es auf kompletten "CRT-Weg" probiert, so wie ihr das Beispiel oben seht. Aber selbst so funktioniert es nicht. Vorher habe ich es mit der WinAPI Funktion "CreateThread" probiert.
Mittlerweile weiß ich absolute nicht mehr weiter und hoffe das ihr vielleicht eine Lösung kennt oder mir Hinweise geben könnt.
Viele Grüße.
ps: Sry für den langen Text. Ich hoffe auch das ich es zu dieser späten Stunde noch mit das Grammatik und der Rächtschraibung hinbekommen habe ;-).
-
char* pcLine = new char();
erzeut einen String mit einem Zeichen Länge. In sprintf formatierst Du aber einen String, der ein klein wenig größer ist als 1 Zeichen. Damit wird natürlich Speicher im Heap überschrieben. Du kannst Dir die Allokation mit new/delete hier aber auch sparen, ein einfaches
char szLine[260]; sprintf(szLine, "Thread %i: counting %i\n", (int)param, i);
reicht völlig aus.
Der Gebrauch von param ist ein klein wenig unsinnig, da param bei Dir in _beginthreadex immer den Wert NULL bekommt.
-
Dank dir!
char* pcLine = (char*)malloc(sizeof(char)*50);
Die zeile hat das ganze dann gelöst nach deinem Hinweis, danke nochmal. Ja, das mit dem param stammt noch aus einer älteren Version, in der ich ein int übergeben habe.
-
ich hoffe du verwendest jetzt auch free() zum freigeben - wenn du schon malloc zum anfordern verwenden musst
tip:
char* p = new char[20]; strcpy(p, "foo"); ... delete [] p;
-
japp, mit free().