Application->ProcessMessages(), SendMessage() oder Thread?



  • Hallo Community,

    habe da mal wieder ein Problem, bei dem ich einen Tip brauchen könnte.

    Ich wähle in einem Formular über ein TabSheet verschiedene Frames dynamisch zur Laufzeit auf. Je nachdem welches Bauteil ich Messen möchte und schließe das nicht mehr benötigte Frame.

    In diesen Frames habe ich einen Start Button und einen Stop Button sowie eine Anzahl der zu Messenden Werte.

    Da das einlesen der Messwerte in einer FOR Schleife passiert, hatte ich das Problem, dass der Stop Button erst nach dem Ende der Bearbeitung abgefragt wurde.

    Also habe ich ein

    Application->ProcessMessages();
    

    in meine Schleife eingebaut, damit die Funktion des Stop - Buttons auch während der Bearbeitung der Schleife gewährleistet ist.

    Ich kann zwar nun meine Messung Stoppen, wenn ich aber während der laufenden Messung über einen Reiter an meinem TabSheet eine andere Komponente auswähle, wird mein Frame beendet und meine Laufende Messung läuft ins Leere und bringt mir eine Speicherverletzung.

    Ich habe nun in meinen Stop Button eine SendMessage Anweisung reinprogrammiert, die soweit auch funktioniert.

    SendMessage(BStart->Handle,WM_STOPMESSAGE,0,0);
    
    void __fastcall TFEineFreq::StopMessage(TMessage& Msg)
    {
       Abbruch = true;
       inherited::Dispatch(&Msg);
    }
    

    Nur wenn ich die Application->ProcessMessage() aus dem Start-Button rausnehme, dann wird diese natürlich auch erst am Ende der Schleifenbearbeitung ausgeführt.

    Die Schleife

    // Schleife mit der Anzahl der Messungen
                         for(int i=1; i<=getAnzahl(); i++)
                            {
                             // Message an Application
                             Application->ProcessMessages();  // <-- Statt dieser Zeile was einfügen?
    
                             // Prüfen ob ein Abbruch gewünscht
                             if(Abbruch == true)
                                     break;
    
                             // Vector Wert mit Messwerte füllen
                             Komponente->Wert.push_back(FSH3.readFSH3());
                            }
    

    Gibt es eine Möglichkeit, wie ich in der Schleife des dem Start-Button sagen kann, HEY da gibt es eine Meldung extra für dich-> STOP JETZT!

    Ich habe so nichts gefunden und bin mir nicht sicher ob ich die Funktion der Messung in einem eigenem Prozess Laufen lassen muß (glaube das heißt Thread) und wie ich das dann umsetze.

    Grüße
    egcactus



  • Ich habe so nichts gefunden und bin mir nicht sicher ob ich die Funktion der Messung in einem eigenem Prozess Laufen lassen muß (glaube das heißt Thread) und wie ich das dann umsetze.

    Nein, Thread != Prozess 🙂
    Also, mit einem Thread würde das schon gehen,
    umsetzen lässt sich das ganz einfach.
    Du machst ein neues Thread Modul und packst deine
    Schleife in die Execute Funktion. Dann machst du dir
    eine Synchronize Funktion mit der du die Daten an den
    Haupt-Thread übergibst. Wenn jemand den Stop Button drückt
    -> MeinThread->Suspend();

    Gruß,

    Max



  • So einfach ist das leider nicht. Die Schleife war nur ein Auszug aus dem Programm.

    Meine Hauptanwendung startet da ein Frame. Und in diesem Frame habe ich meinen StartButton, StopButton, ProzessBar und eben die Eingabefelder.

    Die Synchronisation mit einem normalem Formular würde funktionieren, das habe ich getestet, aber was mache ich, wenn mein Frame weggeschaltet wird. Mein Frame wird in diesem Fall (da dynamisch erzeugt) gelöscht. Die Synchronisation aus dem Thread mit dem Frame wäre auch nicht mehr gegeben.

    Wenn ich nur die Schleife in den Thread reinnehme habe ich keine Aktualisierung der Prozessbar und des Labels welches mir die aktuell zu Messende Frequenz anzeigt mehr.

    Soll ich nun die Frames aus dem Programm rausnehmen und durch normale Fenster ersetzen. Oder kann ich den gesamten Frame im Thread laufen lassen Wobei ich mir noch nicht überlegt habe, was das für Auswirkungen hätte.



  • egcactus schrieb:

    wenn ich aber während der laufenden Messung über einen Reiter an meinem TabSheet eine andere Komponente auswähle, wird mein Frame beendet

    Hast du das so programmiert? Wenn ja, dann beende die Messung doch vor dem Zerstören der Frame-Instanz!?



  • Da obwohl es unterschiedliche Frames sind, eigentlich immer nur ein Frame aktiv sein kann, habe ich das so programmiert, das immer der neu erstellte Frame als AktuellFrame betitelt wird.

    So kann ich in jeder neuen Komponente die ich aufrufe einfach durch die ersten drei Programmzeilen sicher gehen, das der richtige Frame beendet wird.

    Code im Hauptformular:

    void __fastcall TFormGrundbild::FEineFreqStandheizung(TObject *Sender)
    {    
     // Überprüfen ob Frame bereits geladen
     if(AktuellFrame)                       // Wenn Frame bereits existiert...
            {
             delete AktuellFrame;           // ...Frame löschen
             AktuellFrame = NULL;           // Zeiger auf NULL setzen
            }
    
     // Frame FStandheizung erstellen
     TFEineFreq* FStandheizung = new TFEineFreq(new TGroupBox(FormGrundbild));
    
     // Frame auf Aktuellen Frame setzen
     AktuellFrame = FStandheizung;          //<-- Das kann immer ein anderer sein!
     // ...
    }
    

    Da aber einige Frames, gleich für mehrere Komponenten benützt werden, prüfe ich nach betätigen des Start Buttons im Frame anhand des Labels für die Überschrift, welche Komponente gemeint ist.

    Code im Frame:

    // Prüfen ob Auswahl Standheizung ist (anhand der Überschrift die geladen wird)
        if(this->LEineFreqEinstellung->Caption == "Standheizung")
          {
           //... darin kommt dann nach einigen Anweisungen für Logger, Geräte eingeschaltet ..., die verschachtelte Schleife:
    
                     // Schleife für Messung mit und ohne Schalter
                     for(int schalter=0; schalter<=1; schalter++)
                        {
                         //...
    
                         // FSH3 auf Messfrequenz einstellen
                         FSH3.setFSH3(getMessfreq());
    
                         // SMU einstellen
                         SMU.setSMU(getMessfreq(),schalter,getPegel());
    
                         // Vector für Mögliche Anzahl Messschritte einstellen
                         Komponente->Standheizung.Container[0].Messung[schalter].
                         resize(1);
    
                         // Aktuelle Messfrequenz anzeigen
                         LMessung->Caption = FloatToStr(1.0 * getMessfreq() /
                                    Komponente->Standheizung.Eigenschaft.
                                    getMassfaktor()) + " " +
                                    Komponente->Standheizung.Eigenschaft.
                                    getMasseinheit();
    
                         // Schleife mit der Anzahl der Messungen
                         for(int i=1; i<=getAnzahl(); i++)
                            {
                             // Message an Application
                             Application->ProcessMessages();
    
                             // Prüfen ob ein Abbruch gewünscht
                             if(Abbruch == true)
                                    break;
    
                             // Vector Standheizung Wert mit Messwerte füllen
                             Komponente->Standheizung.Container[0].
                             Messung[schalter][0].Wert.push_back(FSH3.readFSH3());
    
                             // Solange Progressbaranzeige nicht auf Maximum...
                             if(ProgressBar1->Position <= ProgressBar1->Max)
                                    {
                                     //... Step hinzufügen
                                     ProgressBar1->StepIt();
                                    }
                            }
    
                         // ProgressBar zurückstellen
                         ProgressBar1->Position = 1;
                        }
    
                     // Wenn Messung durchgelaufen
                     if(Abbruch != true)
                            {
                             // Messung stoppen
                             BStop->Click();
                            }
                    }
    
          }
    
    //... Weiterer Code
    

    Da einige Komponenten vorkommen und jede Komponente auch eine Dauermessung drin hat, kann ich einige Abfragen reinmachen.

    Eine weitere Idee die mir so eingefallen ist, wie wäre es, wenn ich gleich nach dem Aufruf

    TFEineFreq* FStandheizung = new TFEineFreq(new TGroupBox(FormGrundbild));
    

    im Hauptformular einen Thread erzeuge in dem ich den ganzen Code für die Messung der Komponente reinpacke. Wenn ich dann im Frame den Startbutton betätige starte ich den Thread und mit Stop beende ich ihn. Wenn umgeschaltet wird, könnte ich so etwas ähnliches machen, wie ich es mit den Frames mache (AktuellThread).

    Ich weiß nur nicht, wie ich von meinem Thread auf die Funktionen von FStandheizung zugreifen kann. Denn wenn ich das versuche im Thread zu programmieren, kennt er nur die Klasse FEineFreq. Etwa so:

    FormGrundbild->FEineFreq->getMessfreq();
    

    Wenn ich aber nur die Klasse angebe habe ich während der Laufzeit keine Werte darin, da sie sich ja in FStandheizung befinden.
    Also hier:

    FStandheizung->getMessfreq();
    


  • Ich hatte mal ähnliche Probleme und habe eine ganze Zeit lang mit ProcessMessages herumgehampelt. Wenn du einen Job hast, der ausgeführt werden soll und nebenbei noch eine GUI bedienen willst, dann lass den Job in einem eigenen Thread laufen und mach die Kommunikation zwischen GUI/Workerthread selbst. Da die VCL nicht thread safe ist musst du noch einen kleinen Umweg über die Synchronize() Funktion gehen, damit dein Thread seine (Zwischen-)Ergebnisse in der GUI anzeigen kann, ist allerdings alles recht einfach.

    Einfachster Fall:
    Beim Erzeugen des Frames kannst du den WorkerThread ebenfalls erzeugen, und beim Schließen des Frames zerstörst du dann den Thread. Voíla.

    Gruß,
    Doc



  • Wie schon erwähnt, bekomme ich irgendwie keinen Zugriff auf meinen Frame.

    Habe versucht den Thread in FormGrundbild (Hauptformular) zu starten. Möchte nun auf den dynamisch erzeugten Frame FStandheizung zugreifen um mir dort die Werte aus den Edit Feldern zu holen, das geht aber nicht, bekomme nur die Meldung, das FStandheizung nicht bekannt ist.

    Das einzige was ich angeben kann. Wäre die Klasse von FStandheizung also TFEineFreq. Da ich die Werte aber in der Instanz habe habe ich natürlich eine Fehlermeldung, dass er nicht weiß was er mir zurückgeben soll.

    Wie kann ich dem Thread im FormGrundbild sagen, dass er mit der Instanz von FStandheizung zusammenarbeiten soll.

    Code aus dem Hauptformular

    void __fastcall TFormGrundbild::FEineFreqStandheizung(TObject *Sender)
    {
     // Überprüfen ob Frame bereits geladen
     if(AktuellFrame)                       // Wenn Frame bereits existiert...
            {
             delete AktuellFrame;           // ...Frame löschen
             AktuellFrame = NULL;           // Zeiger auf NULL setzen
            }
    
     // Frame FStandheizung erstellen
     TFEineFreq* FStandheizung = new TFEineFreq(new TGroupBox(FormGrundbild));
    
     // Frame auf Aktuellen Frame setzen
     AktuellFrame = FStandheizung;
    
     //...
    
     // Zugehörigkeit zum Grundbild festlegen
     FStandheizung->Parent = FormGrundbild;
    
     // Frame anzeigen
     FStandheizung->Show();
    
     // ...
    
    //<<----an dieser Stelle wird Thread gestartet und sollte irgendwie Zugriff auf FStandheizung erhalten ---->>
    
     // Thread erzeugen
     TEineFreqThread *FThread = new TEineFreqThread(false);
    
     // Thread auf Aktuellen Thread setzen
     AktuellThread = FThread;
    }
    


  • Dann übergib doch dem Thread einfach das Frame als Parameter im Konstruktor...



  • Also irgendwie bekomme ich das nicht hin.

    Ich habe das nun mal so im Header von Thread angegeben:

    __fastcall TEineFreqThread(bool CreateSuspended,TFrame *Sender);
    

    in der cpp Datei :

    __fastcall TEineFreqThread::TEineFreqThread(bool CreateSuspended,
                    TFrame *Sender) : TThread(CreateSuspended)
    {
     FreeOnTerminate = true;
     TFEineFreq *EineFreq = dynamic_cast<TFEineFreq*> (Sender);
    }
    

    Gut ich kann nun in diesem Fastcall auf die Daten zugreifen, aber ich kann nicht in der Execute Funktion auf die Instanz zugreifen. Irgend was mache ich falsch.

    Zugriff auf mein eigentliches Frame, welches ich ja im Hauptformular erstelle habe ich ja nun nur noch in der Fastcall Funktion. Die Synchronize Befehle würden mir ja nun nichts mehr bringen.

    Ich dachte, ich müßte die VCL Elemente über Synchronize synchronisieren, weil diese nicht Thread sicher seien.

    Habe da einen Denkfehler oder ein Verständnisproblem mit diesem Thread.

    Kann mir jemand einen Hinweis geben wo ich den Fehler mache oder hat jemand einen Link zu einer gut verständlichen Beschreibung zu diesem Thread.

    Habe zwar schon im Tutorial reingeschaut:
    http://bcb-tutorial.c-plusplus.net/Thread/index.html

    aber das was in dem Tutorial mit dem StartThreadButton gemacht wird, Und der Angabe, dass die Instanz nun in der ganzen Klasse zu sehen, sei, Funktioniert in meinem Testprogramm nicht und in meinem Projekt schon gar nicht.

    Hier bekomme ich die Meldung: FNewThread Undefiniertes Symbol;

    void __fastcall TForm1::StartThreadButtonClick(TObject *Sender)
    {
      FNewThread = new TMyThread(false); //Jetzt haben wir eine in der ganzen Klasse sichtbare Instanz.
      FNewThread->OnTerminate = DeleteThread;
    }
    

    Ganz nach dem Motto: Irgendwer hat immer eine Antwort 😉



  • Dir scheinen aber noch ein paar grundlegende C++ Kenntnisse zu fehlen.
    Du solltest doch wissen, wie man eine Member-Variable in einer Klasse deklariert und darauf zugreift? (auch TEineFreqThread ist eine ganz normale Klasse)



  • Hallo Th69,

    das war nicht ganz die Antwort die ich mir erhofft habe. Aber ich gebe dir Recht, dass ich mich noch nicht seit Jahren mit C++ beschäftige. Ich hatte drei Jahre C in der Schule (ein mal pro Woche C Unterricht für 2 Schulstunden).

    Das was ich über C++ weiß, lerne ich aus Büchern und vor allem aus diesem Forum, weil ich einige Funktionen in meinem Projekt benötige, die mit C nur sehr umständlich oder gar nicht zu realisieren sind.

    Wenn du mir nun sagst, dass ich keine Membervariablen angelegt habe, dann meinst du sicher die normalen Variablen im Private Bereich.

    Ich habe dort diese Variablen angelegt:

    //-- Variablen ------------------------------------------------------
            unsigned long int messfreq;             // Messfrequenz
            int pegel;                              // Pegel
            int anzahl;                             // Anzahl
            bool dauermessung;                      // Dauermessung
            //-------------------------------------------------------------------
    

    Ich habe diese auch mit den Werten von TFEineFreq beschrieben und habe einen Zugriff eben mit meinen Initialisierten Werten 0.

    Wenn ich versuche in meiner TEineFreqThread Klasse die Klasse für TFEineFreq anzulegen. (Header Datei)

    TFEineFreq *EineFreq;
    

    Und dabei spielt es keine Rolle ob ich sie im Private oder Testhalber im Public Bereich reinschreibe die Fehlermeldung:
    Typname erwartet, in Deklaration fehlt ; ungültige Verwendung von typedef 'exception'

    Gebe ich nun

    class TFEineFreq Test;
    

    im Public Bereich ein bekomme ich die Fehlermeldung Undefinierte Struktur TFEineFreq.

    Meine Headerdatei für diese Klasse TFEineFreq ist eingebunden und da ich
    das so auch in anderen Klassen mache, verstehe ich das nicht.

    Also muß ich entweder Thread anders behandeln oder ich habe da einen Fehler

    Oder ich muß einen anderen Konstuktor für meine TEineFreqThread Klasse anlegen, aber sobald ich das mache:

    TEineFreqThread(TFEineFreq &a);
    

    bekomme ich die Fehlermeldung, das die Deklaration nicht abgeschlossen wäre.

    Wo kann ich denn nun meine grundlegenden Kenntnisse vertiefen und mein Problem nachlesen?



  • Ok, dann mal extra für dich:

    // in EineFreqThread.h

    class TFEineFreq; // forward declaration
    
    class TEineFreqThread
    {
    public:
      __fastcall TEineFreqThread(bool CreateSuspended, TFEineFreq *frame);
    
      virtual void __fastcall Execute();
    
    private:
      TFEineFreq *m_frame; // member
    };
    

    // in EineFreqThread.cpp

    #include "EineFreqThread.h"
    #include "FEineFreq.h"
    
    __fastcall TEineFreqThread::TEineFreqThread(bool CreateSuspended, TFEineFreq * frame)
     : TThread(CreateSuspended), m_frame(frame) // member initialization
    {
     FreeOnTerminate = true;
    }
    
    void __fastcall TEineFreqThread::Execute()
    {
      // ...
    
      // use of frame
      m_frame->SomeMethod(); // call of your frame method
    
      // ...
    }
    

    Und nun noch das Erzeugen des Threads:

    TEineFreqThread *my_thread = new TEineFreqThread(false, FStandHeizung);
    // ...
    

    Wenn du wiederum Zugriff auf den Thread innerhalb deiner Form-Klasse benötigst, dann mußt du auch "my_thread" als Member-Variable in deiner Form-Klasse anlegen.

    Du solltest dir noch mal den Unterschied zwischen lokalen Variablen und Klassen-Variablen (Membern) klarmachen.

    So ich hoffe, das hilft dir...



  • Hallo Th,

    erstmal vielen herzlichen Dank für deine Hilfe. Ich habe ein wenig gebraucht um diese Vorgehensweise richtig zu verstehen. Habe nun also dem jeweiligem Thread meine Frames übergeben. Diese Codezeilen habe ich entfernt:

    // Frame auf Aktuellen Frame setzen
     AktuellFrame = FStandheizung;
    

    Da ich an dieser Stelle ja den Frame dem Thread übergebe und nicht mehr in meinem Hauptformular habe.

    Ich kann jetzt alle Aufgaben im Frame erledigen, dadurch brauche ich in der Execute Funktion so gut wie keine Anweisungen.

    Ich habe nun in meinem Hauptformular noch einige Codezeilen eingefügt:

    // Auf EineFreq Thread casten
     TThreadEineFreq *EineFreq = reinterpret_cast<TThreadEineFreq*> (AktuellThread);
    
     // Prüfen ob ein MessungsThread bereits läuft
     if((AktuellThread) && (EineFreq->Status() != true))
       {
        // Meldung ausgeben
        ShowMessage("Eine Messung läuft bereits");
       }
     else
       {
        // Wenn ein Thread besteht
        if(AktuellThread)
            {
             // Thread löschen
             DeleteThread();
            }
    

    In der DeleteThread Funktion führe ich folgenden Code aus:

    void TFormGrundbild::DeleteThread(void)
    {
     // Thread terminieren
     AktuellThread->Terminate();
    
     // AktuellThread auf NULL setzen
     AktuellThread = NULL;
    }
    

    Was ich da aber nun nicht ganz verstehe ist: Wenn ich nur AktuellThread->Terminate(); ausführe, dann habe ich nicht das Gefühl, dass mein Thread auch beendet wird. Zumindest muß ich ihn explizit auf Null setzen, damit ich ihn wieder benutzen kann und wird mein Frame jetzt eigentlich noch gelöscht oder wird er mit dem Thread einfach deleted?

    Ich rufe ja kein Delete von dem Frame mehr auf. Kann ich das im Borland Compiler irgendwo nachschauen, ob der noch reservierten Speicher für das Frame hat oder ob der Freigegben wird.

    Normalerweise hatte ich sonst in CodeGuard immer die Meldung, dass noch Speicher verwendet wird, aber die kommt nicht.

    Vielleicht ist das auch schon richtig so.

    Grüße und nochmals vielen Dank.
    egcactus



  • Hi, schön, daß du es verstanden hast -)

    Bzgl. der Freigabe des Frames:
    es kommt darauf an, wen du als Owner (d.h. als Konstruktor-Parameter) beim Frame angegeben hast. Wenn du Application oder ein Formular angegeben hast, dann wird der Frame automatisch beim Schließen der entsprechenden Komponente freigegeben. Nur wenn du 0 (NULL) angegeben hast, bist du selber für die Freigabe verantwortlich.

    Wenn der Frame nur von dem Thread benutzt wird, dann könntest du ihn beim Beenden des Threads mitfreigeben (dementsprechend 0 als Frame-Parameter eintragen).

    Und bzgl. TThread-Terminate():
    diese Methode sorgt nur dafür, daß die Variable 'Terminated' gesetzt wird und meistens hat man im Thread die folgende Schleife:

    void __fastcall TMyThread::Execute()
    {
        while (!Terminated)
        {
           // ...
        }
    }
    

    Aber schau dir mal die Erklärung in der BCB-Hilfe zu den einzelnen TThread Eigenschaften und Methoden an.



  • Hallo Th, ich habe die while Funktion bereits drin gehabt, nur eben so wie unten programmiert. Nun habe ich etwas erschreckendes feststellen müssen.

    Sobald ich mein Frame in den Thread übergebe geht meine CPU Auslastung auf 100% hoch. Und kommt nur wieder runter, wenn ich das Projekt beende.

    Wie es aussieht liegt es gerade an dieser Schleife. Mein Thread fragt, darin ab ob im Frame der Stop Button betätigt wurde und gibt dies dann an mein Hauptformular zurück.

    void __fastcall TThreadEineFreq::Execute()
    {
     // Ausführen solange nicht terminiert
     while(!Terminated)
     {
      // Frame Abbruch Variable in Thread übernehmen
      Abbruch = m_frame->getStatus();               //<<-- Diese Abfrage treibt die CPU auf 100% Auslastung 
     }
    }
    
    bool TThreadEineFreq::Status(void)
    {
     // Status zurückgeben
     return Abbruch;
    }
    

    Das treibt die CPU Auslastung an die Grenze. Wie ich aber sonst aus meiner Membervariable (Frame) einen kontakt zu meinem Hauptformular herstellen soll, ist mir wohl doch nicht ganz klar.

    Habe probiert die priority auf tpIdle zu setzen um nur im Leerlauf die Funktion abzuarbeiten, hat aber auch keine Auswirkung. Muß ich dem da noch irgedwo eine Art PauseMillisekunde spendieren. Kenne sowas aus LabView, da haben die Schleifen so eine Millisekunde als Warteanweisung gebraucht, damit die Funktion nicht mit 100% CPU Auslastung abgearbeitet wurde.

    Hast du da eine Idee?



  • Ja, du mußt dem Thread auch mal eine Pause gönnen:

    Sleep(0); // gestattet Umschaltung zu anderen Threads, aber ansonsten läuft der Thread weiterhin im Turbo-Modus
    // oder
    Sleep(1); // oder beliebiger anderer Wert (in Millisekunden!!!)
    

    Wenn du wirklich nur diese Abfrage drin hast, dann reicht auch ein Sleep(100) oder noch höherer Wert (je nachdem wie schnell der Thread reagieren soll).



  • Super, da bin ich aber beruhigt. Dachte ich müßte da eine größere Änderung vornehmen.

    Ich habe wirklich nur diese Abfrage im Thread drin, da alle weiteren Funktionen in meinem Frame abgearbeitet werden.

    Zur Erstellung des Frames mache ich das so:

    TFEineFreq* FStandheizung = new TFEineFreq(new TGroupBox(FormGrundbild));
    

    Und eigentlich habe ich den dann im Grundbild deletet. Muß ich wahrscheinlich noch mal abändern da ja mein Hauptformular erst zum Programmende beendet wird. Was mich aber gewundert hat, war das ich im Code Guard keine Fehlermeldung bekommen habe, Speicher Leaks. Kann ich unter Borland eigenlich nachschauen, welche Threads von diesem Programm noch laufen?



  • Soviele Fragen auf einmal -)

    Aber zuersteinmal: jetzt frage ich mich aber, warum du überhaupt einen Thread verwendest und was in der Funktion frame->getStatus() passiert (denn diese kann ja auch nur passiv einen Wert abfragen)???

    Dann noch zu deinem Konstruktor:
    warum erzeugst du eine GroupBox (die ja noch nicht einmal einen Parent zugewiesen bekommen hat) und verwendest nicht direkt das Formular als Owner?

    Und die laufenden Threads kannst du im Builder unter "Ansicht/Debug-Fenster/Threads (Strg+Alt+T))" anzeigen (sofern du einen Haltepunkt gesetzt hast).

    Und zu den Speicherleaks kann ich dir nichts Genaueres sagen, da ich dein ganzes Programmkonstrukt nicht so ganz durchschaue (ich habe nur den Eindruck, du machst es komplizierter als es eigentlich ist -).



  • Als ich mit dem Projekt begonnen habe, war es noch nicht so kompliziert aufgebaut. Ich habe einfach über mein TabSheet in dem ich verschiedene Buttons habe meine unterschiedlichen Frames aufgerufen.

    Das hat alles sehr gut Funktioniert, bis ich nicht mehr mit Beispielwerten und der CPU Geschwindigkeit getestet habe, sondern reale Hardware dran hatte.

    Da hat sich gezeigt, dass wir für einen Messwert ca 1 Sekunde brauchen um den aufzunehmen. Da allein die Komponente FM (Radio) mit einem Frequenzband von 88 MHz bis 108 MHz bei einem Messschritt von 0,1 MHz aufgezeichnet werden soll. Dazu kommt noch, dass jeder Messschritt ca 10 Mal gemessen wird und das einmal mit und einmal ohne eingeschaltetem Frequenzgenerator und da waren wir bei 4000 Sekunden, also 1 Stunde und 11 Minuten für eine Komponente. Und wir haben mehrere.

    Da hat sich dann gezeigt, dass der Stop Button natürlich nicht funktionierte. Also habe ich Application->ProcessMessages(); eingefügt.

    War dann soweit super, ließ sich stoppen, nur weil ich aber meinen aktuellen Frame ja wie bereits in diesem Thread beschrieben einer übergeordetem Framevariable übergeben habe um in jedem Frame den letzten aktuellen zu Killen hatte ich den neuen Fehler, dass ich Speicherverletzungen bekam. Deshalb der Thread.

    Wobei sich da nun noch ein neues Problem gezeigt hat. Meine Drucken Funktion die ich auf den Aktuellen Thread ausgerichtet hatte funktioniert auch nicht mehr, weil mein Frame ja nun in einem Thread läuft. Aber das bekomme ich hin.

    Zu frame->getStatus()
    In meinem Frame habe ich immer noch die Application->Process() befehle drin, da ja wie bereits erwähnt meine Schleifen sehr lange laufen. Wenn der Button Stop betätigt wird, wird also im Frame eine Variable Abbruch auf true gesetzt. Diese hole ich mir im Thread ab und gebe sie dem Hauptformular.

    Warum ich eine GroupBox erzeuge das ist schon eine ganze Weile her, aber ich weiß, dass ich die ganze Zeit Probleme mit irgend etwas hatte bis ich das so gemacht habe.

    Speicher Leaks habe ich nun keine mehr, habe mir eine Funktion geschrieben in der ich zum Schluss alle dynamisch erzeugten Elemente lösche, falls eines noch offen ist.



  • OK, dann hoffe ich, daß DU das Projekt noch beherrschst (und nicht umgekehrt -)


Anmelden zum Antworten