Mein Thread haut mir die Hufe wech...



  • Aloha,

    habe diverse Threads über Threads ( lol ) gelesen, aber nicht die Beantwortung meines Probs gefunden.

    Ich habe eine Klasse namens Form1.

    Diese beinhaltet diesen tollen Workerthread ( nennt man dies so ? ).

    // in der form1.h
    static UINT check_mail(LPVOID);
    
    // in der form1.cpp
    UINT CForm1::check_mail(LPVOID pParam)
    {
    
        hier wird eine InternetConnection aufgemacht und ein FTP - Server nach bestimmten Dateien befragt.
    
    }
    

    Ich habe das Vorgehen von Henkesoft gemopst...
    Ich starte den Thread in der OnInitialUpdate der Formviewklasse per Timer alle 5 Minuten zum Beispiel.

    SetTimer(1,30000,NULL);
    
    void CForm1::OnTimer(UINT nIDEvent) 
    {
    	switch(nIDEvent){
    
    	case 1:
    
    		AfxBeginThread (check_mail, this);
    		break;
    
    	}
    
    	CFormView::OnTimer(nIDEvent);
    }
    

    Der Workerthread benötigt je nach Verbindung und ob etwas gedownloaded werden muß ca. 10sec bis 30 sec.

    Wenn der Thread nu am rödeln ist, und brav nach Dateien auf dem FTP-Server Ausschau hält, und ich gleichzeitig das Proggi schließe, sehe ich, daß das Proggi nicht sauber geschlossen wird, sondern es bilden sich Memory-Leaks.

    Ist mir ja auch klar, der Thread ist noch mitten drinne, z.B. durchforstet er gerade Verzeichnisse auf dem Server, dann haue ich ihm die Füße weg, indem ich auf das kleine Kreuzchen in der rechten oberen Ecke drügge...

    Wie bekomme ich mein Programm dazu auf das Verlassen von Thread zu warten bis es sich schließt, oder wie beende den Thread sauber mittendrin ( was die schlechtere Variante wäre, wenn er gerade irgendetwas wichtiges macht ).

    Es gibt zwar keinen Absturz momentan, aber es bleiben laut debugger memory leaks, und das ist Hackerscheiße...

    Beste Grüße

    BOA



  • Hi!

    Als erstes: AfxBeginThread() liefert dir einen Zeiger auf check_mail zurück, den retten.

    Z.B. so:

    m_myThread = (check_mail*)
    		AfxBeginThread(
    		RUNTIME_CLASS(check_mail),
    		THREAD_PRIORITY_NORMAL, 0, CREATE_SUSPENDED);
    

    Bevor du jetzt Close-Message bearbeitest, machst du das:

    if(m_myThread)
        {
        DWORD dwExitCode;
        ::GetExitCodeThread(m_myThread->m_hThread,&dwExitCode);
        if(dwExitCode == STILL_ACTIVE)
            {
            ...
    

    Nun kannst du deinem myThread entweder eine Nachricht schicken, dass er nun endlich mal zur Ruhe kommen soll:

    m_myThread->PostThreadMessage(_CHECK_MAIL_BEENDEN,0,0);
    if(WaitForSingleObject(m_myThread->m_hThread,1000) == WAIT_TIMEOUT)
        {
    

    Wieder den Exitcode abfragen:

    ::GetExitCodeThread(m_myThread->m_hThread,&dwExitCode);
    if(dwExitCode == STILL_ACTIVE)
        {
    

    In kurzerhand killen:

    ::TerminateThread(m_myThread->m_hThread,0);
    

    Oder wieder zum Anfang springen und so lange warten, bis check_mail endlich fertig ist. Irgendwann würde ich aber mal die Notbremse ziehen, wenn es nach dem 10. Durchlauf immer noch nicht gut ist. Oder besser noch per MessageBox den Benutzer fragen, was nun geschehen soll.

    Ach, ich würde dem check_mail-Thread (wenn du ihn nicht killst) etwas Zeit zum aufräumen geben, sonst hast du trotzdem memory leaks.

    Gruß A.K.



  • Aloha Andreas,

    vielen Dank für die ausführliche Antwort.

    Um diesen Codeteil ausführen zu können, muß ich dem Thread ja beibringen, Nachrichten empfangen zu können.

    m_myThread->PostThreadMessage(_CHECK_MAIL_BEENDEN,0,0);
    if(WaitForSingleObject(m_myThread->m_hThread,1000) == WAIT_TIMEOUT)
        {
    

    Laut MSDN nutze ich dafür PeekMessage, das ich folgendermaßen innerhalb des Threads implementiert habe :

    MSG t_msg;
    
    while(1){
    
         // hier passiert alles mögliche
    
         PeekMessage(&t_msg,NULL,WM_USER,WM_USER,PM_NOREMOVE);
         if(t_msg.message == KILL_TIMER_THREAD)
    	break;
    
    }
    
    return 0;
    

    Ich tippe, daß ich mich bei PeekMessage glatt anstelle, falsche Parameter setze oder an der falschen Stelle aufrufe.

    Ich werd wahnsinnig 😡 , denn wenn ich den Thread einfach per

    ::TerminateThread(m_myThread->m_hThread,0);
    

    kille, habe ich immer noch die Memory Leaks.

    Ich muß den Thread zum normalen return 0; führen, dann sollte es funzen, dazu muß er aber auf die geworfene Nachricht reagieren.

    Grüße

    BOA



  • Hi!

    Klar bei TerminateThread() hast du wieder Memory Leaks. ⚠

    Der sauberste Weg ist wirklich zu schauen ob der Thread noch läuft und falls dem so ist, den Benutzer darüber zu informieren, dass noch Hintergrundaktivitäten am laufen sind.

    Bricht er dann ab, schickst du deinem Thread 'n Message.

    Ein anderer 'harter' Weg: Verhindere das Schließen des Hauptfensters während des Transfers. 😞

    Solltest du das mit der Message nicht hinbekommen, kann ich abends noch mal nachschauen, wie ich das damals bei meinem Verzeichnisüberwachungs-Thread geregelt habe. 🙂

    Gruß A.K.



  • Hi,

    verwende eine der Synchronisierungsklassen:

    CEvent
    CSemaphore
    CMutex
    CCriticalSection
    

    um ein "Statusanzeigeobjekt" herzustellen.
    Dieses aktivierst du, wenn der Thread beendet werden soll (der Thread muss natürlich auch immer wieder darauf zugreifen und sich ggf. beenden).

    Grüße Rapha



  • Andreas Kapust schrieb:

    Hi!

    Klar bei TerminateThread() hast du wieder Memory Leaks. ⚠

    Der sauberste Weg ist wirklich zu schauen ob der Thread noch läuft und falls dem so ist, den Benutzer darüber zu informieren, dass noch Hintergrundaktivitäten am laufen sind.

    Bricht er dann ab, schickst du deinem Thread 'n Message.

    Ein anderer 'harter' Weg: Verhindere das Schließen des Hauptfensters während des Transfers. 😞

    Solltest du das mit der Message nicht hinbekommen, kann ich abends noch mal nachschauen, wie ich das damals bei meinem Verzeichnisüberwachungs-Thread geregelt habe. 🙂

    Gruß A.K.

    Aloha,

    auch wenn ich es "hinbekomme", würde mich das Thema weiterhin interessieren, soll heißen, wäre klasse, wenn Du noch einmal nachschauen könntest.

    Fühl Dich erstmal virtuell geküßt für die bisherigen Tip(p)s. 😉

    @Rapha

    thx erstmal, werde mich mal mit den Klassen schlaumachen, wie diese mir nützen könnten.

    Ich berichte...

    Grüße und Danke

    BOA



  • Hi

    in der MSDN (zumindest bei mir VC++ 6.0) gibts eine Ziemlich gute Anleitung (auf Deutsch) zu Threads (schließen, synchronisieren,...)

    Du gelangst folgendermaßen hin:
    Öffne die Hilfe der MSDN zu AfxBeginThread, scroll ganz runter, klick auf den Link "Multithreading: Creating Worker Threads" und in "Multithreading: Erstellen von Worker-Threads" dann oben auf den Link "Übersicht". Viel Spaß

    Grüße Rapha



  • Rapha schrieb:

    Hi

    in der MSDN (zumindest bei mir VC++ 6.0) gibts eine Ziemlich gute Anleitung (auf Deutsch) zu Threads (schließen, synchronisieren,...)

    Du gelangst folgendermaßen hin:
    Öffne die Hilfe der MSDN zu AfxBeginThread, scroll ganz runter, klick auf den Link "Multithreading: Creating Worker Threads" und in "Multithreading: Erstellen von Worker-Threads" dann oben auf den Link "Übersicht". Viel Spaß

    Grüße Rapha

    Thx a lot,

    mache ich gleich mal...

    Grüße

    BOA


Anmelden zum Antworten