Es hat sich ja mittlerweile schon herumgesprochen, dass man _beginthread(ex) anstatt CreateThread verwenden sollte, wenn man die CRT verwendet. Die Frage ist wie steht es nun mit _beginthread(ex) und AfxBeginThread wenn man die MFC verwendet?
Es ist ähnlich wie bei der CRT, es gibt auch für die MFC einen Thread State, der im Thread Local Storage abgelegt wird. Zu diesem Thread Local Storage gehören z.B. die temporären Maps für die Fensterverwaltung und Maps für GDI-Objekt Verwaltung. Auch für Tooltips und diverse OLE Funktionen werden in diesem Module Thread State Daten abgelegt.
Weiterhin werden einige Hooks gesetzt, die notwendig werden, wenn GUI verwendet wird. Dito Aufräumarbeiten, falls COM verwendet wird… (AfxOleInit)
Dieser Thread Local Storage wird normalerweise beim Zerstören des assoziierten CWinThread wieder freigegeben. Wird die Threadfunktion verlassen oder AfxEndThread aufgerufen, dann wird der Thread Module State mit dem entsprechenden Speicher freigegeben.
Was passiert, wenn man in einem MFC Programm einen Thread mit _beginthreadex startet und anschließend MFC Funktionen verwendet und dann mit _endthread den Thread terminiert?
Was passiert, wenn man mit AfxBeginThread einen Thread startet und ihn mit _endthread terminiert ❓
❗ Dann entsteht ein Leak, und je nach verwendeten Komponenten kein kleines ❗
Sollte die MFC Applikation also dynamisch Threads erzeugen, weil damit zum Beispiel Sockets überwacht werden oder andere nette Workerthreads bedient werden, dann kann man relativ schnell unerfreuliches erleben.
Es gilt also 2 Dinge zu beachten:
- In einem MFC Programm sollte man immer AfxBeginThread verwenden! Man geht sonst das Risiko ein, dass bei der Verwendung der ersten MFC Funktion (AfxGetResourceHandle o.ä.) ein entsprechender Speicherblock angelegt wird und eben sonst nicht mehr freigegeben wird..
- Und beim Verlassen einer Threadfunktion kümmert man sich am Besten gar nicht darum, wie der Thread gestartet wurde . Man muss explizit AfxEndThread gar nicht aufrufen. Man sollte einfach alle Threadfunktionen einfach durch return verlassen. Der Thread wird dann entsprechend der Funktion, die man beim Start gewählt hat auch terminiert. Dann bleibt – auch bei einer Änderung der Umgebung , ob nun mit oder ohne MFC.
Anmerkung:
Warum werden diese Leaks nicht in der Debugausgabe angezeigt? Ganz einfach, weil diese Allokationen durch die MFC nicht getrackt werden. Das Speichertracking der Debugversion wird explizit für diese Allokationen ausgeschaltet.