Thread SOFORT beenden



  • Hallo,
    leider geht keiner auf den anderen Thread ein und ich brauche dringend Fortschritte.

    Das Problem ist soweit isoliert, dass ein anderer Thread in OnDestroy() beendet/zerstört werden muss. Da das Programm ja gerade schon schließt scheiden Methoden wie Nachrichten übergeben aus.

    Wie kann ich einen Thread von meinem Main-Thread aus sofort beenden?

    Grüße,
    Pedro



  • Am sichersten schließt du einen Thread "von innen" - d.h. der Thread überprüft selber in regelmäßigen Abständen ein bool-Flag des Hauptprogramms (oder einen Event), ob er abgebrochen werden soll, und beendet sich im Ernstfall.

    Auf die harte Tour geht es per TerminateThread() (aber das würde ich nur empfehlen, wenn der Thread sich komplett aufgehängt hat - das nimmt dir nämlich die Möglichkeit, die threadeigenen Ressourcen aufzuräumen).


  • Mod

    Noch einmal die Warnung: TerminateThread sollte nicht verwendet werden!
    Wenn der Thread irgendwelche Ressourcen blockiert, dann werden diese evtl. nicht freigegeben. Dein Programm wird sich dann etwas später evtl. ganz aufhängen!

    Mach es wie CStoll sagt. Der Thread sollte selbst einfach returnieren. Also in Deinem OnDestroy, setzt Du für den Thread ein Event und wartest bis der Thread terminert.



  • Soweit so gut, folgendes klappt:

    void CHSIDepotmanagerDlg::OnDestroy()
    {
    CDialog::OnDestroy();
    master_shutdown = true;	
    WaitForSingleObject(stockdata_thread->m_hThread, INFINITE);
    }
    
    UINT CHSIDepotmanagerDlg::load_stockdata_masterthread(LPVOID pParam)
    {
    CHSIDepotmanagerDlg* pDlg	= (CHSIDepotmanagerDlg*) pParam;
    pDlg->child_param.pointer	= pDlg;
    
    //	Vorbereitung des CProgress-Fensters
    	int length = pDlg->m_stockCtrl.GetItemCount();
    	pDlg->m_progress_dialog.init(0,length);
    	pDlg->m_progress_dialog.show();
    	pDlg->m_progress_dialog.setText("Laden der historischen Kursdaten ...");
    	int stock_index=0;
    
    	while(pDlg->master_shutdown==false && stock_index<pDlg->m_stockCtrl.GetItemCount())
    	{
    	Beep(1000,100); Sleep(500);
    
    	// pDlg->load_stock_data(stock_index);
    	stock_index++;
    	}
    
    return true;
    }
    

    Sobald ich aber die load_stock_data Funktion reinnehme, wird der Thread nicht mehr mit dieser Methode beendet. Liegt das jetzt daran, dass OnDestroy nur ein paar ms zur Beendigung hat oder liegt das an meiner load_stock_data Funktion?

    Hier ist sie mal total abgespeckt, denn schon der Anfang klappt nicht.
    Ich greife ja auch ein CListCtrl (stockCtrl) zu. Kann es sein, dass dieses schon gelöscht ist und die Funktion deshalb nicht richtig beendet? Wenn ja, wie kann ich sicherstellen, dass das CListCtrl noch existiert, wenn ich darauf zugreife?

    BOOL CHSIDepotmanagerDlg::load_stock_data(int stock_index)
    	{
    	bool abbruch, start_set=false;
    	CString strLesePuffer, error, substring, start_date, end_date;
    	CStdioFile	DateiLesen;
    
    	CString stock_symbol, filename, fullpath, header;
    	stock_symbol	        =	m_stockCtrl.GetItemText(stock_index,0);
    	filename		=	stock_symbol;	
    	filename.Replace(".","_");	filename += ".csv";
    	fullpath		=	path_stock_data + "\\" + filename;
    	header			=	"Date,Open,High,Low,Close,Volume,Adj. Close*";
    
    	return true;
    	}
    


  • Okay, zu mindest das Problem, dass der Thread nicht korrekt beendet wird, liegt nicht am CListCtrl. Ich habe mal die Abfrage der CListCtrl rausgenommen und trotzdem funktioniert die Abfrage nicht.

    Danke für eure Mühe!!!



  • So wie du Threads einsetzt kann das nix werden, du setzt keinerlei Syncronisationsobjekte ein (CriticalSection unter Windows, bzw Mutex, Semaphore).

    Auf Controls sollte ausserdem nur aus dem Parent Window (deine Haupt-Applikation) zugegriffen werden. dH Progress per Messages aus dem Thread an deine Hauptanwengung senden.

    Alternative Beendungsmöglichkeit für deinen Thread -> Eigene Messageloop.

    Dadurch wirds die Fehler geben nehm ich jetzt mal an.

    *edit*



  • Hier ist sie mal total abgespeckt, denn schon der Anfang klappt nicht.

    Also ich kann hier nichts fehlerhaftes erkennen (außer dem Problem, daß du eventuell auf nicht mehr existierende Fenster-Elemente zugreifen könntest - aber afaik darf eigentlich nur der Thread auf ein Fenster zugreifen, der es auch erzeugt hat, nicht deine Arbeitsthreads).



  • Kann auch nur nochmal wiederholen wie CStoll schon sagte wenn du weiterhin direkt auf Controls des Hauptfensters aus Workerthreads zugreifst wirst du massive Probleme bekommen. Hab das auchmal gemacht sogar mit ca 20 Threads aber das ist reine Glückssache das sowas funktioniert und dauernd gehen die Threads kaputt die du dann neu erzeugen musst etc.

    So wie du das momentan machst würde man die OnIdle Funktion des Hauptfensters nutzen sofern du Timer einsetzten willst anstatt Threads.



  • Warum baruche ich ne Thread-Synchronisation, wenn es nur einen Thread gibt, der auf die entsprechenden Steuerelemente zugreift?

    Und folgendes führt auch zu Debug Assertion failed (afxcmn2.inl Line 288)

    UINT CHSIDepotmanagerDlg::load_stockdata_masterthread(LPVOID pParam)
    	{
    		CHSIDepotmanagerDlg* pDlg			= (CHSIDepotmanagerDlg*) pParam;
    		pDlg->child_param.pointer			= pDlg;
    
    			//	Vorbereitung des CProgress-Fensters
    			int length = pDlg->m_stockCtrl.GetItemCount();
    			pDlg->m_progress_dialog.init(0,length);
    			pDlg->m_progress_dialog.show();
    			pDlg->m_progress_dialog.setText("Laden der historischen Kursdaten ...");
    
    			int stock_index=0;
    
    			while(pDlg->master_shutdown==false && stock_index<pDlg->m_stockCtrl.GetItemCount())
    			{
    				Beep(1000,100); Sleep(500);
    
    				pDlg->load_stock_data(stock_index);
    				stock_index++;
    			}
    }
    
    	BOOL CHSIDepotmanagerDlg::load_stock_data(int stock_index)
    	{
    		int			pos,			last_pos,	length,		ssatz_ident;
    		bool		abbruch=false,	start_set=false;
    		CString		stock_symbol,	filename,	fullpath,	header;
    		CString		strLesePuffer,	error,		substring,	start_date,		end_date;
    		CStdioFile	DateiLesen;
    
    		stock_symbol	=	"ADS_DE";	//m_stockCtrl.GetItemText(stock_index,0);
    		filename		=	stock_symbol;
    		filename.Replace(".","_");	
    		filename		+= ".csv";
    
    		fullpath		=	path_stock_data + "\\" + filename;
    		header			=	"Date,Open,High,Low,Close,Volume,Adj. Close*";
    
    		progress_setPos(stock_index);
    }
    
    BOOL CHSIDepotmanagerDlg::progress_setPos(int pos)
    {
    	m_progress_dialog.setPos(pos);
    	return true;
    }
    
    void CProgress::setPos(int index){
    	m_ctlProgress.SetPos(index);
    }
    

    Jetzt wird doch nur noch auf Steuerelemente vom jeweiligen Parent zugegriffen und trotzdem ein Fehler. Gibt es eine Funktion mit der ich überprüfen kann, ob der Prozess-Dialog bzw. das entsprechende Steuerelement noch existiert?



  • Deine Hauptapplikation ist doch auch ein Thread also sinds schonmal 2 die auf den gleichen Dialog zugreifen.

    Und überprüfung ob Dialog noch da ist:
    zB mit Assert kannste das machen.
    Aber warum setzt du nicht einfach einen Breakpoint mal dahin?

    Und ne Zeilennummer von externer Quelle hilft gar nicht weiter, Schau doch mal im Call Stack an welcher Stelle (in deinem Source Code) er überhaupt das Problem hat.


Anmelden zum Antworten