Nach einiger zeit Deadlock? MFC Thread



  • Hallo, hab ein Problem mit meinem Programmchen.
    Hab ein Dialogbasierendes GUI in der ich einen workerthread starte.

    void CDialogDlg::OnBUTTONThreadGo() 
    {
          m_Flag = 1; 
       CWinThread* pThread = AfxBeginThread (Thread, this); 
    }
    
    UINT CDialogDlg::Thread(LPVOID pParam) 
    { 
       Thread* pThreadKlasse = (Thread*)pParam; 
       pThreadKlasse->ThreadFunktion();
       return 0; 
    }
    
    void CDialogDlg::ThreadFunktion()
    {
      while(m_Flag)
      {
       //Methoden von CDialogDlg die z.b. auch auf Editcontrols schreiben etc.
      //Zugriff auf eine Progressbar optional
      }
    }
    

    So nun zum Problem. Also das mit der ProgressBar hab ich mir schon angeschaut. Das macht man mit Handles (PostMessage,Sendmessage). Hab ich aber erstmal weggelassen. Das eigentliche Problem ist sind die Methoden von CDialogDlg die ich im Thread aufrufe, die z.b. texte in Editcontrols schreiben. Es Funtkioniert, allerdings nicht sehr lang. Mal 2 Stunden, mal 10 Stunden. Also ich lasse in dem Thread immer Zyklen durchlaufen um ständig etwas zu prüfen. Irgendwann jedoch hält das programm einfach an und ich weiß nicht warum. 😞
    Ich kann den thread noch "anhalten" wenn ich auf Stop klicke, aber im Taskmanager ist dieser immernoch zu sehen und sobald ich das Programm beenden möchte hängt es sich komplett auf.

    Die Methoden verwende ich aber auch Teils bei einderen Aktionen, die nicht in einem Thread laufen, daher möchte ich die Ausgabe auf die Edits ungern da raus lösen, bzw. weiß ich nicht was dies ändern würde.

    Kann mir jemand Helfen? Ich habe keinen Schimmer und bin leider nicht so begabt in C++



  • Du darfst aus anderen Threads nicht auf UI-Elemente zugreifen.



  • Jo Danke ich weiß 😉 Nur leider hilft mir dieser gut gemeinte Ratschlag nicht weiter.

    Ein Hinweis noch: Ich habe anfangs mal probiert die ProgressBar mittel .SetPos() in dem Thread zu setzen. hat auch funktionier (ich weiß man darf das nicht machen) nur kam der Deadlock dann eher. Ich würde eigentlich nur gern wissen, was genau den Deadlock verursacht? Sind es irgendwelche nachrichten die die MessagePump zum "überlaufen" bringen oder wie?

    Jedenfall ohne die Progressbar läuft das Programm länger, aber nicht unbegrenzt. Irgendwann bleibt es hängen (der Thread, die GUI ist weiterhin ansprechbar). Gibt es für Editboxen auch Nachrichten Handler mit denen ich die CStrings da rein schreiben kann? bzw. darf man das überhaupt machen? Ich benötige ja eigentlich nur so eine Art status-Meldung aus dem Thread. Wie könnte man das erreichen? Danke schonmal an alle 🙂



  • Wenn DU es weisst, warum machst Du es dann trotzdem?
    Sende Dir eine Nachricht "WM_APP+x"!



  • Weil ich nicht weiß wie es anders geht 😕

    Ich hab das immer versucht zu vermeiden mit Nachrichten zu arbeiten. wäre das in etwa so:

    PostMessage(WM_APP+20 , parameter , 0)   //wobei +20 zufällig gewählt wurde und der parameter dann mein "Fortschritt" wäre
    

    Ich muss ja Postmessage nehmen, weil sonst der Thread auf einen Rückgabewert warten würde richtig?

    Und wie frage ich die Nachricht im Dialog ab beziehungsweise wie merke ich das sie ankommt? Tut mir leid wenn die Fragen vielleicht für den ein oder anderen unter dem niveau liegen, ich bin noch neu in dem gebiet



  • MrDeadlock schrieb:

    PostMessage(WM_APP+20 , parameter , 0)   //wobei +20 zufällig gewählt wurde und der parameter dann mein "Fortschritt" wäre
    

    Ja, zum Beispiel so.

    Ich muss ja Postmessage nehmen, weil sonst der Thread auf einen Rückgabewert warten würde richtig?

    Richtig. SendMessage hätte keinen Vorteil gegenüber SetPos, was intern nämlich auch nur ein SendMessage macht.

    Und wie frage ich die Nachricht im Dialog ab beziehungsweise wie merke ich das sie ankommt?

    Mit einem ON_MESSAGE Eintrag in der Message-Map.
    http://msdn.microsoft.com/en-us/library/k35k2bfs.aspx

    Sonst kannst du auch den "Progress" in Member-Variablen speichern, und den Zugriff auf diese Progress-Daten über eine eigene Mutex synchronisieren.
    Dabei musst du natürlich aufpassen dass du "nichts" aufrufst während du diese Mutex gelockt hältst - zumindest nichts was zu Problemem (Deadlocks) führen könnte.

    Also z.B. so:

    #define WM_MY_PROGRESS_UPDATE (WM_USER + 123)
    
    class MyFooDialog : public CDialog
    {
    ...
        void SetProgress(int progress, CString progressMessage)
        {
            {
                CSingleLock lock(&m_progressCS, true);
                m_progress = progress;
                m_progressMessage = progressMessage;
            }
    
            PostMessage(WM_MY_PROGRESS_UPDATE, 0, 0);
        }
    
        void GetProgress(int& out_progress, CString& out_progressMessage)
        {
            CSingleLock lock(&m_progressCS, true);
            out_progress = m_progress;
            out_progressMessage = out_progressMessage;
        }
    
        LRESULT OnMyProgressUpdate(WPARAM, LPARAM)
        {
            int progress;
            CString progressMessage;
            GetProgress(progress, progressMessage);
    
            m_guiControl1.SetPos(progress);
            m_guiControl2.SetText(progressMessage);
        }
    
    private:
        CCriticalSection m_progressCS;
        int m_progress;
        CString m_progressMessage;
    
    ....
    }
    

    EDIT:
    Verbesserung, damit die Message-Queue nicht mit WM_MY_PROGRESS_UPDATE zugespamt wird, falls der GUI-Thread aus irgendeinem Grund arg hinterherhinkt:

    void SetProgress(int progress, CString progressMessage)
        {
            CSingleLock lock(&m_progressCS, true);
            m_progress = progress;
            m_progressMessage = progressMessage;
    
            if (!m_progressUpdatePending)
            {
                m_progressUpdatePending = true;
                PostMessage(WM_MY_PROGRESS_UPDATE, 0, 0);
            }
        }
    
        void GetProgress(int& out_progress, CString& out_progressMessage, bool clearProgressUpdatePendingFlag)
        {
            CSingleLock lock(&m_progressCS, true);
            out_progress = m_progress;
            out_progressMessage = out_progressMessage;
            if (clearProgressUpdatePendingFlag)
                m_progressUpdatePending = false;
        }
    
        LRESULT OnMyProgressUpdate(WPARAM, LPARAM)
        {
            int progress;
            CString progressMessage;
            GetProgress(progress, progressMessage, true);
    
            m_guiControl1.SetPos(progress);
            m_guiControl2.SetText(progressMessage);
        }
    
    private:
        CCriticalSection m_progressCS;
        bool m_progressUpdatePending; // init auf = false
        int m_progress;
        CString m_progressMessage;
    
    ....
    


  • ps:
    Für solche Dinge wäre eine "post if not already/still in queue" Funktion gut... gibt's aber unter Windows glaube ich nicht. Schade.

    Und da PeekMessage() nicht mit "fremden" Fenstern funktioniert, kann man es sich nichtmal nachbauen... 😞


  • Mod

    Das hier nur um den Progress geht, warum also keinen Timer setzen unddas im UI Thread prüfen.
    Also ganz auf ein PostMessage verzichten.



  • Nein, es geht nicht nur um den Progress. Ich möchte auch Statusmeldungen unter anderem an 2 Statics und ein Edit senden (anzeigen). Dafür sende ich mir 2 Nachrichten um 4 Variablen zu zwei unterschiedlichen Zeitpunkten übertragen zu können.

    Danke an alle, ihr habt mir sehr geholfen! Speziellen Dank an hustbaer! 👍

    Btw: gibt es eine Trick mit der MSDN zurecht zu kommen? Irgendwie bin ich immer überfordert damit. Ich finde nie das, was ich brauch 😞


  • Mod

    1. Dann kannst Du einfach ein Timer benutzen und eine Queue in der die Nachrichten stehen.
    2. Ich suche Begriffe in der MSDN mit Google und gebe MSDN immer als Teilwort mit an.



  • DeadlockAde schrieb:

    Btw: gibt es eine Trick mit der MSDN zurecht zu kommen? Irgendwie bin ich immer überfordert damit. Ich finde nie das, was ich brauch 😞

    Da hilft eigentlich nur Erfahrung.

    Is jetzt kein blöder Spruch sondern ernst gemeint. Irgendwann hat man mal raus wie OS-API Dinge im allgemeinen so funktionieren, kennt die wichtigsten Begriffe, und dann findet man sich in der MSDN auf einmal toll zurecht.

    Wobei die MSDN auch nur ne API-Referenz ist, bzw. ein paar API-spezifische Dinge auf höherer Ebene erklärt. High-Level Erklärungen zu allgemeinen nicht API-spezifischen "Programmier-Dingen" wirst du in der MSDN eher vergeblich suchen.


Anmelden zum Antworten