Workerthread aus der Hauptapplikation beenden

hphi

Mitglied
Hallo liebes Forum,

ich habe noch ein Problem.
In meiner Applikation gibt es ein Workerthread, was im Hintergrund ständig die Datenbank abfragt und ein ListCtrl aktualisiert. Dies funktioniert auch gut, nur beim beenden habe ich ein Problem. Ich habe schon einige Tage gegoogelt aber noch keine befriedigende Lösung gefunden.

Hier ist ein Ausschnitt meines codes:

Code:
...

class CBpViewSoundPlay : public CResizableFormView
{
protected: // Nur aus Serialisierung erzeugen
	CBpViewSoundPlay();
	DECLARE_DYNCREATE(CBpViewSoundPlay)
                ...
private:
                ...
	UINT wait4state();
               static UINT thread_entry(LPVOID lpvoid) 
	{        
	    return static_cast<CBpViewSoundPlay*>(lpvoid)->wait4state();    
	}
	void updateLstCtrl(int, int, const char*, const char*, const char*, const char*);
	void run() 
	{        
	    m_hStopThread	 = CreateEvent(0, FALSE, FALSE, "StopThread");
	    m_hThreadStopped = CreateEvent(0, FALSE, FALSE, "ThreadStopped");
	   ::AfxBeginThread(thread_entry,this);    
	} 
	void stop()
	{
	    if ( m_hStopThread )
	        ASSERT(SetEvent(m_hStopThread));
	    if ( m_hThreadStopped ) 
	        WaitForSingleObject(m_hThreadStopped, 20000);
	}
	HANDLE	m_hStopThread;
	HANDLE	m_hThreadStopped;
	CString m_csConnectStr;
};

In der Formview - Klasse versuche ich mein Thread durch folgenden code in der OnDestroy-Funktion zu beenden:

Code:
//-----------------------------------------------------------------------------
void CBpViewSoundPlay::OnDestroy() 
{
    stop();
    ...
    CResizableFormView::OnDestroy();
    ...
}
//-----------------------------------------------------------------------------

Das Thread wird folgendermaßen gestartet:

Code:
// inline
void run() 
{        
   m_hStopThread	= CreateEvent(0, FALSE, FALSE, "StopThread");
   m_hThreadStopped = CreateEvent(0, FALSE, FALSE, "ThreadStopped");
   ::AfxBeginThread(thread_entry,this);    
}

Die Thread - Funktion:
Code:
//-----------------------------------------------------------------------------
UINT CBpViewSoundPlay::wait4state()
{
       while ( true )
       {
          ...
          // mache ganz schön viel
          ...
          if ( WaitForSingleObject(m_hStopThread, 500) == WAIT_OBJECT_0 )
          {
	SetEvent(m_hThreadStopped);
	break;
         }
    }
    return 0;
}

Diese Lösung soll folgendermaßen funktionieren: Das Hauptprogramm setzt das Event
m_hStopThread. Die Thread-Funktion kommt in den Code im if von
if ( WaitForSingleObject(m_hStopThread, 500) == WAIT_OBJECT_0 )

und setzt wiederrum das Event m_hThreadStopped, das signalisiert wird, dass die Thread-
Funktion sich jetzt beendet hat. Solange wartet das Hauptprogramm mit dem OnDestroy.

So die Theorie, die nur in 96% der Tests funktioniert.
In den Rest der Fälle wird die FormView zerstört, obwohl die Thread - Funktion noch die
ListView aktualisiert, d.h. die Events werden nicht vernünftig erkannt.

Es gibt noch CriticalSection und Mutexe. Leider weis ich nicht, wie dies funktioniert.
Kann mir jemand helfen?

Viele Grüße

hphi
 
An sich ist dein Vorgehen schon korrekt.

Allerdings musst du beim Warten auf den Thread aufpassen. Ggf. arbeitet der gerade mit dem Fenster und verlässt sich drauf, dass du noch Messages abarbeitest. D.h. ein WaitForSingleObject mit einem kleinen Timeout, alle Messages bearbeiten (Da gibt's ein verstecktes, äusserst praktisches AfxPumpMessage) und dann wieder WaitForSingleObject aufrufen. Solange, bis dein Thread wirklich beendet ist.
 
Da, wo du jetzt on OnDestroy nur deinen WaitForSingleObject-Aufruf hast, baust du eine Schleife hin:

Code:
      SetEvent( m_hCloseEvent );

      MSG   msg;

      while ( true )
      {
        Sleep( iSleepDelay );

        DWORD dwResult = WaitForSingleObject( m_hThreadStopped, 0 );
     
        if ( dwResult == WAIT_OBJECT_0 )
        {
          // Thread hat sich beendet
          break;
        }
        if ( PeekMessage( &msg, NULL, 0, 0, PM_NOREMOVE ) )
        {
          GetMessage( &msg, 0, 0, 0 );
          TranslateMessage( &msg );
          DispatchMessage( &msg );
        }
      }
 
Hallo Endurion,

vielen Dank. Das funktioniert jetzt. 50x öffnen und schließen des Fensters, und kein
Absturz. Sauber.

Viele Grüße und Danke

hphi
:)
 

Neue Beiträge

Zurück