Korrektes Beenden einer Dialoganwendung incl. Worker-Threads

L

lg2000

Hallo,

habe mit VC2003 eine dialogbasierte Anwendung geschrieben. Darin laeuft ein Worker-Thread, der in einer seperaten Klasse CCounter realisiert ist. Beim Beenden der Anwendung ueber das X oder das Systemmenu sollen sowohl der Thread als auch die Anwendung korrekt beendet werden.

Die WM_CLOSE Nachricht fange ich in der Dialog-Klasse mittels der OnClose-Methode ab und rufe darin eine Methode der CCounter-Klasse auf, um den Thread ordnungsgemaess zu beenden. Laut System-Ausgabe scheint dies auch korrekt zu funktionieren: "Der Thread '_threadstartex' (0x240) hat mit Code 0 (0x0) geendet."

Leider wird die Anwendung nicht korrekt beendet. Beim Druecken des X verschwindet zwar das Dialogfenster aber die Anwendung scheint immer noch aktiv zu sein. Die Systemmeldung im DevStudio lautet: "Das Programm "[2392] DaysCounter.exe: Systemeigen" wurde mit Code 2 (0x2) beendet." Ausserdem erscheint der entsprechende Prozess im Windows Task-Manager weiterhin.

Wer kann mir helfen?

Gruss lg2000
 
Hallo,
Die WM_CLOSE Nachricht fange ich in der Dialog-Klasse mittels der OnClose-Methode ab...

Leider wird die Anwendung nicht korrekt beendet. ... Ausserdem erscheint der entsprechende Prozess im Windows Task-Manager weiterhin.
Hier würde ich evtl. einen Zusammenhang sehen, ist aber schwer zu sagen, ohne den Source näher gesehen zu haben. Lässt du den WM_CLOSE denn weiterlaufen, wenn er nichts mit deinen Threads zu tun hat, oder fängst du ihn pauschal ab und schmeißt ihn dann weg?
 
Hallo,

moechte eigentlich nur erreichen, dass beim Beenden des Programmes alle laufenden Threads korrekt beendet werden. Habe versucht, das ganze folgendermassen zu loesen:

// Hiermit wird der Thread gestartet
void CCounter::Start()
{
if (m_endTime != 0)
{
m_bThreadController = true;
m_pThread = AfxBeginThread(ThreadFunc, (LPVOID)this, THREAD_PRIORITY_NORMAL);
ASSERT(m_pThread);
if (m_pThread)
{
m_pThread->m_bAutoDelete = false;
}
}
else
{
TRACE("m_endTime has to be set first!");
}
}

// Hiermit wird der Thread beendet
void CCounter::Stop()
{
DWORD dwExitCode;

m_bThreadController = false;

CSingleLock(&m_killEvent, true);
do {
Sleep(1);
TRACE("WAIT...");
::GetExitCodeThread(m_pThread->m_hThread, &dwExitCode);
} while (dwExitCode == STILL_ACTIVE);

if (m_pThread != NULL)
{
delete m_pThread;
m_pThread = NULL;
}
}

// statische Thread-Methode ruft klasseninterne Methode Calculate auf
// Diesen "Kunstgriff" habe ich lediglich gewaehlt, um keine globalen Variablen nutzen zu muessen
UINT CCounter::ThreadFunc(LPVOID pParam)
{
UINT rc = -1;
CCounter* pCall = (CCounter*)pParam;
if (pCall)
{
rc = pCall->Calculate();
}
return rc;
}

UINT CCounter::Calculate()
{
m_bRunning = true;
while(m_bThreadController)
{
Tick();
Sleep(100);
}
m_killEvent.SetEvent();
m_bRunning = false;
return 0;
}

// CDaysCounterDlg ist der Dialog meiner Dialoganwendung
// Hier soll der noch laufende Thread explizit beendet werden
void CDaysCounterDlg::OnClose()
{
DWORD dwExitCode;
if (m_pCounter)
{
m_pCounter->Stop();
}
CDialog::OnClose();
}

Gestartet wird der Thread in OnInitDialog mittels m_pCounter->Start();

Wann wird eigentlich der Destruktor des Dialogs aufgerufen? Nach OnClose oder schon davor?
 
Hat denn bisher keiner ein aehnliches Problem gehabt? Wie werden denn noch laufende Threads beim Beenden der Anwendung ordnungsgemaess terminiert? So ein Mechanismus muesste doch in jeder Windows-Anwendung vorhanden sein...

Bin fuer jeden Hinweis dankbar!

lg2000
 
Da du da eine normale Variable zum Beenden benutzt (m_bThreadController), solltest du diese vorsichtshalber als volatile deklarieren. Sonst kann der Compiler wider besseren Wissens annehmen, dass diese innerhalb des Threads immer konstant bleibt und die Prüfung wegoptimieren.

Noch besser wäre es, auch dafür auf ein richtiges Event zu warten. Du hast ja schon eins als Ende-Bestätigung.
 

Neue Beiträge

Zurück