progi kackt ab bei thread beenden ...



  • hallole,

    folgende problemsituation:
    habe eine dialogbasierte anwendung. im hauptdialog wird ein berechnungs-thread gestartet und gleich danach ein unterdialog mit einer progress-bar angezeigt.
    der berechnungs-thread aktualisiert die progressbar. mein code sieht ungefaehr so aus:

    // zunaechst einige deklarationen zum unterdialog:
    // Benutzerdef. Signale ...
    #define WM_USER_THREAD_FINISHED (WM_USER+0x101)
    #define WM_USER_THREAD_UPDATE_PROGRESS (WM_USER+0x102)
    
    // der unterdialog vom Typ CProgressDlg hat zwei message handler:
    class CProgressDlg : public CDialog{
    // ...
    afx_msg LRESULT OnThreadFinished(WPARAM wParam,LPARAM lParam);
    afx_msg LRESULT OnThreadUpdateProgress(WPARAM wParam,LPARAM lParam);
    // ...
    };
    
    // .. und folgende implementierung fuer messages ...
    LRESULT CProgressDlg::OnThreadFinished(WPARAM wParam,LPARAM lParam){
    	MessageBox("Thread has exited");
          CDialog::OnCancel();
    	return 0;
    }
    
    LRESULT CProgressDlg::OnThreadUpdateProgress(WPARAM wParam,LPARAM lParam){
    	CProgressCtrl *pb = (CProgressCtrl *) GetDlgItem(IDC_PRGS);
    	pb->SetPos(100*(int)wParam/(int)lParam);
    	return 0;
    }
    // ... (messages sind zudem manuell in die message-map eingefuegt worden)
    
    // ----------------------------
    // fuer thread-info ...
    typedef struct THREADINFOSTRUCT {
    	CProgressDlg *ptr2prgDlg;
    } THREADINFOSTRUCT;
    
    // hauptdialog berechenung starten ...
    void CHauptDlg::startCalc(){
    
          CProgressDlg *pd = new CProgressDlg(); 
          THREADINFOSTRUCT *ti = new THREADINFOSTRUCT;
    	ti->ptr2prgDlg = pd;
    
    	CWinThread *pThread = AfxBeginThread(test, ti);
    	if(pd->DoModal()==IDCANCEL){
               // hier Thread abbrechen ...
    	     pd->PostMessage(WM_USER_THREAD_FINISHED,0,0);
    	}
    }
    
    // Thread-Funktion ...
    UINT CHauptDlg::test(LPVOID lParam){
    
    	THREADINFOSTRUCT* tis = (THREADINFOSTRUCT*) lParam;
    	for (int i=0;i<100;i++) {
    		tis->ptr2prgDlg->PostMessage(WM_USER_THREAD_UPDATE_PROGRESS,i,100);
    		Sleep(100);
    	}
    	tis->ptr2prgDlg->PostMessage(WM_USER_THREAD_FINISHED,0,0);
    
    	delete tis;
    	return 0;
    }
    

    Mein problem ist das alles korrekt ablaeuft. nur wenn ich auf Abbrechen Button im unterdialog wahrend der berechnung klicke kackt mir mein programm ab.

    warum kann das sein??

    vieeeeelen dank.

    grussle



  • Möchtest du ernstgenommen werden?
    Hältst du "kackt ab" für eine professionelle und hilfreiche Fehlerbeschreibung?
    Hast du bedacht, was passiert, wenn GetDlgItem fehlschlägt?



  • also hier nochmal eine "proffessionelle" (uuuh 🙄 hoert sich das toll an) beschreibung der situation fuer MFK:

    Das Programm stuerzt nach klicken auf den abbrechen Button im unterdialog ab und es gibt eine assertion failed message.

    es geht denke ich nicht darum das GetDlgItem nicht funzt sondern darum,
    das mein gestarteter thread auf member meines unterdialoges zugreift.
    Da aber nun der Druck auf den Abbrechen knopf den unterdialog schliesst, ist der weitere zugriff auf member des unterdialogs durch den thread mit schwierigkeiten verbunden. Ich denke das ist der hauptsaechliche fehler.

    vorrangig geht es um folgende zeilen ...

    CProgressDlg *pd = new CProgressDlg(); 
        THREADINFOSTRUCT *ti = new THREADINFOSTRUCT; 
        ti->ptr2prgDlg = pd; 
        CWinThread *pThread = AfxBeginThread(test, ti); 
        if(pd->DoModal()==IDCANCEL){ 
               // hier Thread abbrechen ... 
             pd->PostMessage(WM_USER_THREAD_FINISHED,0,0); 
        }
    

    meine frage lautet (sofern meine obige vermutung richtig ist):

    wie kann ich den thread (beim klicken auf den abbrechen button im unterdialog) stoppen!?!?!?

    gruss



  • hat keiner ne ideee dazu? 😞 😕



  • kummerle schrieb:

    also hier nochmal eine "proffessionelle" (uuuh 🙄 hoert sich das toll an) beschreibung der situation fuer MFK:

    Tut mir leid, ich dachte, du wolltest nicht wie ein Kiddie behandelt werden. Kommt nicht wieder vor 🙂

    Das Programm stuerzt nach klicken auf den abbrechen Button im unterdialog ab und es gibt eine assertion failed message.

    Wenn du jetzt noch den Text der Fehlermeldung verrätst, ist das fast schon eine gute Fehlerbeschreibung. 😉

    es geht denke ich nicht darum das GetDlgItem nicht funzt sondern darum,
    das mein gestarteter thread auf member meines unterdialoges zugreift.

    Ich lehne mich jetzt vielleicht etwas weit aus dem Fenster, aber ich vermute, GetDlgItem ist ein Member deines Unterdialogs.

    wie kann ich den thread (beim klicken auf den abbrechen button im unterdialog) stoppen!?!?!?

    Indem du ein Flag setzt, das der Thread regelmäßig abfragt.



  • hier eine noch genauere beschreibung des problems...:

    1. mein hauptdialog erstellt einen thread ...
      ...
      AfxWinThread(...)
      ...

    2. gleich danach wird ein modaler unterdialog erzeugt und angezeigt welcher einen abbrechen button hat.
      ...
      CUnterDialog ud;
      ud.DoModal();
      ...

    3. der thread beinhaltet eine (laengere) berechnung an dessen ende dem unterdialog aus 2) eine bestimmte nachricht per PostMessage verschickt wird und somit der unterdialog geschlossen wird.

    Wie kann ich nun dem thread klarmachen, dass wenn ich auf den abbrechen-button im unterdialog gehe der unterdialog geschlossen worden ist und somit fuer den thread (z.b. um eine progressbar zu aktualisiere) NICHT mehr verfuegbar ist.

    Angenommen ich erzeuge mir ein member-flag in meinem unterdialog der auf true gesetzt ist wenn er angezeigt wird anderfalls false.

    wie sollte dann der thread wissen das diese flag nun auf false ist?? ich kann ja nicht in jeder zeile meiner threadfunktion dieses flag abfragen!?

    ich vermute ich muss das vielleicht wieder mit messages machen !?!

    vielen dank vorab.

    gruss



  • kummerle schrieb:

    hier eine noch genauere beschreibung des problems...:

    Wie schon mehrfach gesagt, der Wortlaut der Fehlermeldung/fehlgeschlagenen Assertion wäre hilfreich.

    ich kann ja nicht in jeder zeile meiner threadfunktion dieses flag abfragen!?

    Es reicht, wenn du das vor jedem Zugriff auf den Dialog machst. Alles andere ist ja unkritisch.



  • Du erzeugst einen Thread und in diesem einen Dialog ?

    Du hast einen Hauptdialog. In diesem erzeugst du einen modalen Dialog. Dieser Dialog erzeugt dann einen Thread. Leite hier am besten ein Klasse von CWinThread ab. Es gibt 2 Versionen von Threads. WorkerThread und "Benutzeroberflächenthreads". Ein Workerthread macht auf eine Oberfläche überhaupt nichts. Deshalb Workerthread. Vom "Benutzeroberflächenthread" kannst du in deinem Dialog abfragen was du möchtest und sogar eine Status ausgeben. Beachte aber das man Variablen Syncronisieren muss wenn 2 Threads (ein Dialog hat auch einen Thread) auf diese Variablen zugreifen. Hier muss sichergestellt werden das ein anderer Thread nicht auf die Variable zugreift wenn einem Thread das Zeitfenster entzogen wird und er noch nicht mit dem schreiben in eine Variable fertig ist.



  • der unterdialog wird im hautpdialog erstellt. dort wird auch der thread erstellt. der modale unterdialog bleibt solange bestehen, bis der thread eine nachricht an den unterdialog schickt zum beenden des unterdialogs (dies geschieht am ende meiner thread-funktion).

    meine frage lautet (nochmal konkreter):
    wie kann ich dem thread, welcher uebrigens ein workerthread ist, mitteilen, dass ich den dialog schliessen will und folglich der thread nicht mehr auf diesen zugreifen kann!?!

    gibt es eine alternativ-methodik fuer mein vorgehen?
    es geht darum eine laengere berechnung (per thread) zu starten und waerend dieser einen unterdialog mit fortschritts-anzeige zu zeigen, der auch einen abbrechen button hat mit dem man die berechnung stoppen koennen soll.

    vielen dank.
    gruss



  • hi kummerle,
    ist schon ne weile her, aber hast du dein problem gelöst?
    hab ne ähnliche anwendung, mein hauptdialog mit workerthread liest daten ein,
    ein unterdialog zeigt den fortschritt an.
    schliese ich jetzt den unterdialog, "kackt mir das programm ab" 😃
    wie bei dir eben,
    jetzt glaube ich das es daran liegt das der dialog vor dem thread geschlossen wird, und ich damit dem thread sein dialog fenster weghau.
    ich sollte also wie ich das dialog fenster schliese den thread abschiessen,
    geht sowas?
    danke
    Al



  • Leider kommt meine Anwort fuer kummerle zu spaet, aber vielleicht kann ich ja Dir, youCanCallMeAl, weiterhelfen:

    Erstmal, Vorsicht bei der Verwendung von Threads. Am besten ist, man koppelt die Threads (in diesem Fall Hauptthread und Workerthread) komplett voneinander ab. Es ist sowieso immer schlecht, wenn es Co-Dependencies zwischen Teilen einer Anwendung gibt.

    Es gibt z.B. WM_COPYDATA, mit der man Nachrichten zwischen Threads verschicken kann.

    Am besten ist, wenn ein Thread jobbasiert arbeitet, d.h. er nimmt einen Auftrag an, fuehrt ihn aus, und schickt eine Antwort.

    Man kann auch Events zur Thread-Synchronisierung benutzen. Aber WM_COPYDATA sollte fuer Deine Zwecke erstmal reichen.

    Weiterfuehrend waere eine eigene Message-Queue-Implementation (z.B. mit std::list oder std::deque), die beim Ankommen einer Nachricht einen Event ausloest. So aehnlich ist das z.B. bei AmigaOS geloest.

    Unter Windows hat man jedoch u.U. das Problem, dass ein GUI-Thread in einer MessageLoop taetig ist, und nicht auf ein Event von ausserhalb warten kann. Dann muss man in diesem Fall entweder mit Window Messages arbeiten, oder die erweiterten Wartefunktionen von Windows benutzen (Name faellt mir grade nicht mehr ein -- benutze zu Hause nur noch Linux).

    Fuer die letzten beiden Loesungen muss man auf jeden Fall ein eigenes Framework schreiben, deswegen ist WM_COPYDATA auf die Schnelle die bessere Loesung, wenn man sowieso eine GUI-Anwendung hat.

    Hoffe, das hilft.

    p.s.: Start und Ende eines Threads sollte man synchronisieren, z.B. mit Events (das ist auch bei GUI-Anwendungen nicht weiter tragisch, solange man Initialisierung und Cleanup einigermassen kurz haelt).



  • erst mal danke für die antwort,
    ich bin nicht sicher ob ich das richtig verstanden habe,
    aber ich denke mein problem ist nicht unbedingt der datenaustausch zwischen threads, vielmehr glaube ich das mein thread erst nach dem dialog in dem er gestartet wird beendet wird, kann das sein?

    bsp:
    ich hab einen thread/while schleife
    while(m==1) {
    ....
    ....
    }
    wird solange durchlaufen bis m!=1,
    kann es sein das ich einen absturz produziere wenn ich jetzt mit closeDialog den dialog schliese in dem der thread gestartet wurde wenn der nicht vorher beendet wurde, also noch mitten in der while schleife steckt und der das setzen auf m=0 zu "spät" kommt?
    dank noch mal



  • Ja, das meinte ich mit Synchronisierung beim Start und Beenden von Threads.

    Mach am besten einen WM_DESTROY Handler fuer den Dialog, signalisiere Deinem Thread, dass er sich beenden soll, und warte dann mit WaitForSingleObject() auf dem Thread-Handle.

    Weiterhin koennen nicht abesicherte gegenseitige Datenzugriffe auch einen Absturz ausloesen. Deshalb: Kommunikation trennen, nicht gegenseitig Code aufrufen. Sonst musst Du wenigstens eine Mutex-Semaphore haben, die verhindert, dass beide Threads gleichzeitig auf bestimmte Daten zugreifen. Denk daran, dass Windows jederzeit Deinen Dialog ueber die Fensterprozedur aufrufen kann (das geschieht eigentlich sogar innerhalb des Kontexts von Windows, wenn SendMessage() verwendet wird).



  • habs kapiert und funktioniert sogar schon,
    danke noch mal!!!! 😃


Anmelden zum Antworten