Freigeben über


Multithreading: Beenden von Threads in MFC

In den beiden folgenden Fällen wird die Beendigung eines Threads ordnungsgemäß ausgelöst: die Steuerungsfunktion wird beendet, oder der Thread darf nicht vollständig ausgeführt werden. Falls z. B. in einem Textverarbeitungsprogramm ein Thread für den Hintergrunddruck verwendet wird, wird die Steuerungsfunktion normal beendet, sobald der Druckauftrag erfolgreich abgeschlossen ist. Wenn der Benutzer den Druckvorgang jedoch abbrechen möchte, muss der Thread für den Hintergrunddruck vorzeitig beendet werden. In diesem Thema wird beschrieben, wie jede Situation zu implementieren ist und wie der Exitcode des Threads nach seiner Beendigung ermittelt wird.

Normale Thread-Terminierung

Von einem Arbeitsthread werden bei der normalen Threadbeendigung folgende einfache Schritte ausgeführt: die Steuerungsfunktion wird beendet und es wird ein Wert zurückgegeben, aus dem der Grund für die Beendung hervorgeht. Sie können entweder die AfxEndThread-Funktion oder eine return-Anweisung verwenden. Normalerweise steht 0 für die erfolgreiche Ausführung; dies ist ganz Ihnen überlassen.

Für einen Benutzeroberflächen-Thread ist der Vorgang genauso einfach: Rufen Sie aus dem Benutzeroberflächen-Thread heraus PostQuitMessage im Windows SDK auf. Der einzige Parameter, den PostQuitMessage annimmt, ist der Exit-Code des Threads. Bei Worker-Threads steht 0 normalerweise für eine erfolgreiche Ausführung.

Vorzeitige Thread-Terminierung

Das vorzeitige Terminieren eines Threads ist fast genauso einfach: Rufen Sie AfxEndThread innerhalb des Threads auf. Übergeben Sie den gewünschten Exitcode als einzigen Parameter. Hierdurch wird die Ausführung des Threads beendet, der Stapel des Threads freigegeben, alle mit dem Thread verbundenen DLLs getrennt und das Threadobjekt aus dem Speicher gelöscht.

AfxEndThread muss von dem zu beendenden Thread aus aufgerufen werden. Wenn Sie einen Thread von einem anderen Thread aus beenden möchten, müssen Sie ein Kommunikationsverfahren zwischen den beiden Threads einrichten.

Abrufen des Exit-Codes eines Threads

Um den Exit-Code des Worker- oder des Benutzeroberflächen-Threads zu erhalten, rufen Sie die Funktion GetExitCodeThread auf. Informationen über diese Funktion finden Sie im Windows SDK. Diese Funktion nimmt den Handle des Threads (gespeichert im m_hThread-Daten Member von CWinThread-Objekten) und die Adresse eines DWORD.

Wenn der Thread noch aktiv ist, setzt GetExitCodeThread STILL_ACTIVE in die übergebene DWORD-Adresse, andernfalls wird der Exit Code in dieser Adresse abgelegt.

Das Abrufen des Exit-Codes von CWinThread-Objekten erfordert einen zusätzlichen Schritt. Standardmäßig wird bei Beendung eines CWinThread-Threads das entsprechende Threadobjekt gelöscht. Dies bedeutet, dass Sie nicht mehr auf den m_hThread-Datenmember zugreifen können, da das CWinThread-Objekt nicht mehr vorhanden ist. Führen Sie zur Vermeidung dieser Situation einen der folgenden Schritte aus:

  • Legen Sie das m_bAutoDelete-Data-Member auf FALSE fest. Auf diese Weise ist ein CWinThread-Objekt auch nach dem Beenden des Threads noch vorhanden. Sie können dann auf den m_hThread-Datenmember zugreifen, nachdem der Thread beendet wurde. Bei dieser Methode müssen Sie das Zerstören des CWinThread-Objekts selbst übernehmen, da es nicht automatisch vom Framework gelöscht wird. Dies ist die bevorzugte Methode.

  • Speichern Sie das Handle des Threads separat. Nachdem der Thread erstellt wurde, kopieren Sie sein m_hThread-Data-Member (mit ::DuplicateHandle) in eine andere Variable und greifen über diese Variable darauf zu. Auf diese Weise wird das Objekt automatisch bei Beendigung gelöscht, und Sie haben dennoch die Möglichkeit, den Grund für die Beendigung des Threads zu ermitteln. Achten Sie darauf, dass der Thread nicht beendet wird, bevor Sie die Möglichkeit hatten, das Handle zu duplizieren. Am sichersten ist es, CREATE_SUSPENDED an AfxBeginThread zu übergeben, das Handle zu speichern und dann den Thread durch den Aufruf von ResumeThread wieder aufzunehmen.

Bei beiden Methoden lässt sich ermitteln, warum ein CWinThread-Objekt beendet wurde.

Weitere Informationen

Multithreading mit C++ und MFC
_endthread, _endthreadex
_beginthread, _beginthreadex
ExitThread