TThread->Terminate() und Destructor wird übergangen???



  • EDIT: Ok da es wohl zu lang ist die Kurzfassung vorweg:

    Im Destructor eines TForms will ich einen TThread beenden. Ich rufe Terminate auf, mache WaitFor und dann delete.

    Dummerweise wird der DEstructor des Threads, den ich neu definiert habe, gar nicht erst ausgeführt. In diesem Destructor des Threads werden weitere Threads terminiert. Das geschieht aber gar nicht erst. Die werden einfach gekillt, OHNE daß der DEstructor aufgerufen wird. Warum?

    Im Grunde simple Konstellation:

    Ein TThread MAIN. Member des TThreads sind 4 weitere TThreads.

    Im Konstruktor des TThreads MAIN werden die 4 anderen angeleiert mit new. Soweit zu gut.

    In jedem Thread habe ich den Destructor neu definiert. Alle Threads befinden sich in einer while(terminated==false) Schleife und spielen State Machine. Alle reagieren auf Events und führen Terminate() aus.

    Jetzt bekommt MAIN von außen sein Terminate. Verlässt die Schleife nachdem er Terminate() ausgeführt hat. Im Destructor von MAIN habe ich quasi ThreadA-> Terminate() etc stehen. Danach ein WaitForMultipleObjects, das auf alle 4 wartet.

    Was passiert? MAIN kriegt sein Terminate, es wird auf MAIN mit WaitFor gewartet und danach delete MAIN... MAIN verlässt also die while Schleife und beendet damit Execute. Eigentlich sollte der doch jetzt in seinen Destructor springen, alle 4 anderen Threads anfunken aund brav warten... Was passiert? Die Sauviecher zeigen in der Ereigniszeiule des Debuggers in dem Moment Thread Ende, indem MAIN aus der Execute kommt.

    Was hab ich denn jetzt schon wieder angestellt??? Kommt mein delete für MAIN zu schnell? Aber mit delete arbeitet MAIN doch erst den Destructor ab???

    Also um jetzt mal schlechten Code zu zeigen... Kleinere Unstimmigkeiten sind beabsichtigt um den Code auf das Wesentliche zu kürzen.terminate sind TEvents in den Threads. Jeder Thread ist zur Zeit mit der gleichen Struktur aufgebaut. Ich bring erstmal die Infrastruktur zum laufen, bevor ich weiter mache.

    Und NEIN das ist nicht die Hungarian Notation. Ich weigere mich.

    _fastcall Controller::Controller(bool CreateSuspended)
    	: TThread(CreateSuspended)
    {
    	//Threads ankurbeln
    motor = new Motor(false);
    	io = new IO(false);
    	improc = new ImageProcessor(false);
    	camcon = new CameraController(false);
    	FreeOnTerminate=false;
    }
    //---------------------------------------------------------------------------
    __fastcall Controller::~Controller()
    {
    	//Hier bin ich noch gar nicht, da sind die Threads schon beendet....
    
    camcon->terminate->Acquire();
    	camcon->terminate->SetEvent();
    	camcon->terminate->Release();
    	improc->terminate->Acquire();
    	improc->terminate->SetEvent();
    	improc->terminate->Release();
    	io->terminate->Acquire();
    	io->terminate->SetEvent();
    	io->terminate->Release();
    	motor->terminate->Acquire();
    	motor->terminate->SetEvent();
    	motor->terminate->Release();
    	HANDLE delhandles [4] = {(HANDLE)camcon->Handle, (HANDLE)improc->Handle, (HANDLE) io->Handle, (HANDLE) motor->Handle};
    	WaitForMultipleObjects(4,delhandles,true,INFINITE);
    	delete camcon;
    	delete improc;
    	delete io;
    	delete motor;
    }
    //---------------------------------------------------------------------------
    
    void __fastcall Controller::Execute()
    {
    	SetName();
    	unsigned short newstate = 0;
    
    	//Thread wiederholt ausführen bis Terminierung
    	while(Terminated==false) {
    
    		//Auf Event aus der Liste eventhandles warten und Index des Events
    		//newstate zuweisen. Wartezeit unendlich.
    		newstate = WaitForMultipleObjects(3,eventhandles,false,INFINITE);
    
    		//Entscheide welcher Zustand
    		switch (newstate) {
    
    			//newstate == Messung
    			case 2 : {
    
    				break;
    			//case 2;
    			}
    
    			//newstate == Initialisierung
    			case 1 : {
    				break;
    			//case 1
    			}
    
    			//newstate == Beenden
    			case 0 : {
    				//Setze terminieren Flag
    				Terminate();
    				//Verlasse switch Anweisung
    				break;
    			} //case 0
    		} //switch
    	} //while
    } //function
    //Zack hier werden alle Threads beendet. Sogar gelöcsht...
    //---------------------------------------------------------------------------
    

    Man verzeihe mir eventuelle falsche Tastenanschläge. Aber ich sitze im Dunkeln und binzu faul das Licht anzumachen. Und irgendwie treffe ich auf dem Notebook nicht immer.



  • So hab mal den Text bissel vereinfacht.

    Also ich hab nach ein wenig probieren immernoch das Problem... Terminiere ich den Hauptthread, so beenden sich die Unterthreads von selbst undefiniert. Die sind doch eigentlich im WaitForMultipleObjects Zustand....



  • //edit: ich sehe gerad, du hast es schon so in etwa...

    Nimm nen Event, was das Beenden signalisiert oder so, dann machste das so in etwa:

    Execute:

    do
     {
      newstate = WaitForMultipleObjects(3,eventhandles,false,INFINITE);
    //rest
     } while(newstat != 0);
    a->~a();
    

    So würd ichs zumindest machen - denke, dass das auch ne soo unelegant ist ^^

    hf gl



  • Ja, über das Problem bin ich auch schon mal gestolpert: http://www.c-plusplus.net/forum/viewtopic-var-t-is-167833-and-start-is-0-and-postdays-is-0-and-postorder-is-asc-and-highlight-is-tthread.html

    Praktisch habe ich es tatsächlich gelöst, wie unskilled es beschrieben hat...



  • Danke für die Tips. Ich bin über deinen Thread schon gestolpert @Joe_M.

    Mein Problem lag darin, daß ich in jedem Thread die gleichen Namen für die Events benutzt habe. DEswegen hat er ALLE Threads abgeschossen als ich den Main beendet habe. Ich habe jetzt OnTerminate=DeleteThread; gesetzt und räume in DeleteThread auf. Und die Events sind nun auf mi anderen Namen versehen. Jetzt funktioniert Thread->WaitFor() auch. Lediglich über WaitForMultipleObjects fliegt er drüber. DEswegen warte ich halt nacheinander auf alle Threads.


Anmelden zum Antworten