Wie realisiert man eine/n Hintergrundscheife / -prozess


  • Mod

    Poste doch deinen Code, dann sieht man das evtl. besser 😉
    Und du solltest dir das Thread example von wxWidgets anschauen.



  • Also folgendes habe ich jetzt aus der thread.cpp datei herausgefunden.

    1. Ich muss ID's definieren. Ich denke so:

    enum
    {
        WORKER_EVENT,
        ...
    };
    

    2. Ich muss eine Event Tabelle anlegen, die dann so aussieht:

    BEGIN_EVENT_TABLE( MyFrame , wxFrame )
        EVT_UPDATE(WORKER_EVENT, MyFrame::OnWorkerEvent)
        ...
    END_EVENT_TABLE()
    

    3. In der Klasse MyFrame muss ich passende Methoden anlegen.

    void OnWorkerEvent( wxCommandEvent& event )
    ...
    

    4. Mein WorkerThread rufe ich so auf:

    MyWorkerThread *worker = new MyWorkerThread( this );
    

    Ich denke, dass mit 'this' das Frame meines Programms übergeben wird.

    5. In der Methode Entry() des WorkerThreads schreibe ich folgendes rein:

    while(1)
    {
        if ( TestDestroy() )
            break;
    
        //Lese Daten vom COM-Port
    
        // Die erste Möglichkeit
        wxCommandEvent event( ich denke hier muss das rein wxEVT_COMMAND_TEXT_UPDATED , WORKER_EVENT);
        event.SetString( strng WasInDieBoxSoll );
    
        wxPostEvent( freame, event );
    
        // oder die andere Möglichkeit
        freame->WriteText(string);
    }
    

    Die Klasse MyFrame und die Klasse MyWorkerThread sind bei mir in zwei verschiedenen Header-Dateien definiert. In der Datei MyFrame.h habe ich natürlich die Headerdatei von MyWorkerThread eingebunden. So wenn ich jetzt die Headerdatei von MyFrame in die Headerdatei von MyWorkerThread einbinden möchte, geht es natürlcih nicht, weil er rekursiv versucht die andere Datei einzubinden.

    Weiß jemand wie sich das lösen lässt, ohne die Klassendefinitonen in eine Datei reinzuschreiben?


  • Mod

    Das Stichwort ist forward Declaration.

    MyThread.hpp:

    class MyFrame;
    
    class MyThread : ...
    


  • also hier mein Code:

    Headerdatei der MyWorkerThread Klasse:

    class MyFrame;
    
    class MyWorkerThread : public wxThread
    {
        private:
            MyFrame *m_frame;
            ctd9300 *CTD;
    
        public:
            MyWorkerThread( MyFrame *frame, ctd9300 *CTD_Temp );
    
            virtual void *Entry();
            virtual void OnExit();
    };
    

    Sourcecode der MyWorkerThread Klasse:

    MyWorkerThread::MyWorkerThread( MyFrame *frame, ctd9300 *CTD_Temp ) : wxThread()
    {
        m_frame = frame;
    
        CTD = CTD_Temp;
    
    }
    
    void *MyWorkerThread::Entry()
    {
        temperature temp_values;
        while( !TestDestroy() )
        {
            temp_values = CTD->getTemp();
    
            m_frame->writeValues( temp_values );
        }
    
        return NULL;
    }
    
    void MyWorkerThread::OnExit()
    {
    }
    

    und nun der Sourcecode der MyFrame Klasse:

    void MyFrame::butt_start_stopClick(wxCommandEvent& event)
    {
        if ( butt_start_stop->GetValue() )
        {
            MyWorkerThread *readTempRC = new MyWorkerThread( this ,CTD );
            readTempRC->Create();
            readTempRC->Run();
        }
        else
        {
            readTempRC->Delete();
        }
    }
    

    ctd9300 ist eine Klasse die ich zur Kommunikation via COM-Port mit meinem µC geschrieben habe. Diese Klasse funktioniert einwandfrei. Der µC sendet permanent Temperaturwerte von den angeschlossenen Sensoren (es sind mehrere). Die Methode getTemp() liefert ein Struct mit allen Temperaturwerten zurück.

    butt_start_stop ist ein ToggleButton.

    Wenn ich jetzt den dargestellten Quellcode compiliere, dann kommt die Fehlermeldung:

    invalid use of undefined type struct MyFrame' (zeile 16 Sourcecode MyWorkerThread) forward declaration ofstruct MyFrame' (zeile 1 Headerdatei MyWorkerThread)

    Würde rein theoretisch das so funktionieren?
    Was kann ich tun um diese Fehlermeldung zu beseitigen?

    Nachtrag 19.06.2007 - 14:04:
    Fehlermeldung beseitigt! Habe in die MyWorkerThread.cpp die datei MyFrame.h includiert.

    Nachtrag 19.06.2007 - 14:06:
    Beim 2. Klick auf den Button butt_start_stop bekomme ich wieder die Fehlermeldung

    MyFrame.exe hat ein Problem festgestellt und muss beendet werden.

    Ich habe das Gefühl, dass ich den Thread nicht richtig beende.
    Kann das sein?


  • Mod



  • Ja ist klar, dass Delete nur bei wxTHREAD_JOINABLE Threads funktioniert. Habe es bereits geändert. Nur bringt das nichts. Der Fehler tritt immernoch auf.



  • KRibel schrieb:

    Ja ist klar, dass Delete nur bei wxTHREAD_JOINABLE Threads funktioniert. Habe es bereits geändert. Nur bringt das nichts. Der Fehler tritt immernoch auf.

    Kann es sein, dass du auf die GUI auf deinem Thread aus zugreifst? Was macht die Funktion

    m_frame->writeValues( temp_values );
    

    ?
    Oder greifst du aus den veschiedenen Threads auf den gleichen Speicherbereich zu?

    Benutz mal einen Debugger und lokalisieren die Stelle, wo der Fehler auftritt.


  • Mod

    hm also:

    void MyFrame::butt_start_stopClick(wxCommandEvent& event)
    {
        if ( butt_start_stop->GetValue() )
        {
            MyWorkerThread *readTempRC = new MyWorkerThread( this ,CTD );
            readTempRC->Create();
            readTempRC->Run();
        }
        else
        {
            readTempRC->Delete();
        }
    }
    

    ^den Code finde ich schon mal sehr komisch.
    Der eine Thread widr lokal erstellt, der andere danach gelöscht.
    Und zwischen Thread und GUI solltest du per Event kommunizieren.



  • m_frame->writeValues( temp_values );
    

    temp_values ist ein Struckt aus drei Strings.
    Die Funktion writeValues ist eine Methode des Hauptframes und schreibt diese drei Strings in eintsprechende EditFelder.

    Das Problem ist, dass selbst wenn meine Entry-Funktion NUR aus einer while-Schleife besteht:

    while( TestDestroy() )
    {}
    

    , dass selbst dann der selbe Fehler auftritt.

    Nachtrag 19.06.07 - 22:43:
    Mir ist da bezüglich gleichzeitigem Zugriff was eingefallen. Das muss ich morgen überprüfen.



  • Zu Testzwecken habe ich mein WorkerThread folgender Maßen geändert:

    class WorkerThread : public wxThread
    {
        private:
            MyFrame *m_frame;
    
        public:
            WorkerThread( MyFrame *frame);
    
            virtual void *Entry();
            virtual void OnExit();
    };
    
    WorkerThread::WorkerThread( MyFrame *frame) : wxThread(wxTHREAD_JOINABLE)
    {
        m_frame = frame;
    }
    
    void *WorkerThread::Entry()
    {
        while( !TestDestroy() )
        {
    
            wxCommandEvent event( wxEVT_COMMAND_TEXT_UPDATED , THREAD_WORKER_EVENT );
            event.SetString( _T( "Test" ) );
            wxPostEvent( m_frame , event );
            wxThread::Sleep(200);
        }
    
        return NULL;
    }
    
    void WorkerThread::OnExit()
    {
    }
    

    Die Methode die beim Event ausgeführt wird sieht so aus:

    void MyFrame::OnMyEvent(wxCommandEvent& event)
    {
        Textfeld->Clear();
        *Textfeld << event.GetString();
    }
    

    Der Text wird eingeblenden wie erwartet.

    Wenn ich debugge und ein Breakpoint vor Delete() setze ist alles in Ordnung. Kliche ich dann auf "Nächster Schritt" kommt die Fehlermeldung:

    Eine Zugriffsverletzung (Segmentation Fault) trat in Ihrem Programm auf.

    Was kann das sein?


  • Mod

    wie erstellst du den Thread zur Zeit?
    Kann es sein, das der Pointer der Delete aufruft, ungültig ist?



  • @phlox81:

    den Code finde ich schon mal sehr komisch.
    Der eine Thread widr lokal erstellt, der andere danach gelöscht.
    Und zwischen Thread und GUI solltest du per Event kommunizieren.

    Oh danke!!! Habe doch MyWorkerThread *readTempRC schon in meiner Headerdatei stehen.

    Habe den Code geändert:

    void MyFrame::butt_start_stopClick(wxCommandEvent& event)
    {
        if ( butt_start_stop->GetValue() )
        {
            readTempRC = new MyWorkerThread( this ,CTD );
            readTempRC->Create();
            readTempRC->Run();
        }
        else
        {
            readTempRC->Delete();
        }
    }
    

    und es funktioniert.

    Muss jetzt noch die passenden Methoden für die ganzen Events schreiben und dann passt es.

    Kann ich eigentlich durch ein Event an mein WorkerThread etwas senden?

    VIELN DANK NOCH EIN MAL!!!


  • Mod

    Wenn du deine Threadklasse auch von wxEvtHandler ableitest, kann sie auch Events empfangen.



  • @phlox81:
    was meinst du mit 'auch'?

    Etwa so?

    class WorkerThread : public wxThread : wxEvtHandler
    

  • Mod

    Ja, Mehrfachvererbung, allerdings ist deine Syntax falsch:

    class MyThread : public wxThread, public wxEvtHandler
    

    ist richtig.


Anmelden zum Antworten