Probleme mit Thread
-
Hallo Tom7,
ich gebe auch mal einen Tipp ab. Bei Label fällt mir spontan ein "Synchronize"void __fastcall TSendFunk::Execute() { int ret = 0; // Fehlercode der Funktionen while (!Terminated) // Endlos-Schleife des Thread { // Warten auf die Ereignisse ret = WaitForMultipleObjects(2, Fu1Event, False, INFINITE); // Ein Thread-Ereignis ist aufgetreten? switch (ret - WAIT_OBJECT_0) { case Thread_Event: { Synchronize(BearbeiteEreignis); // Ereignis bearbeiten break; } // Thread beenden case Thread_End: { Terminate(); // beenden des Thread break; } default: { // Fehler in den Logfile schreiben ErrText->msgErrorExt (IDATNFUNK, IFEHLER, "[TSendFunk::Execute]", " Ein unbekanntes Ereignis ist aufgetreten!"); break; } } // Ende: switch (ret - WAIT_OBJECT_0) } // Ende: while (!Terminated) } // Ende: Funktion // Den Puffer der Funktegramme abfragen ob Daten vorhanden sind und // senden wenn die Funkstrecke frei ist. void __fastcall TSendFunk::BearbeiteEreignis(void) { ........ {Die Hilfe sagt dazu:
"Die Methode Synchronize führt innerhalb des VCL-Haupt-Threads einen Methodenaufruf aus.typedef void __fastcall (__closure *TThreadMethod)(void);
void __fastcall Synchronize(TThreadMethod &Method);Beschreibung
Synchronize löst den Aufruf einer bestimmten Methode aus, die vom VCL-Haupt-Thread ausgeführt werden soll. Durch dieses indirekte Verfahren werden Konflikte in Multithread-Anwendungen vermieden. Wenn Sie nicht sicher sind, ob ein Methodenaufruf Thread-sicher ist, rufen Sie die Methode vom VCL-Haupt-Thread aus auf, indem Sie sie an die Methode Synchronize übergeben.
Der Thread wird unterbrochen, während die angegebene Methode ausgeführt wird."
Viel Refolg
evi48
-
ok:
in der ControlHWRead steht folgendes:
if(Hardware->bCOMPort==true){ //*1 for(int i=0;i<16;i++){ Hardware->fTMP[i]=Hardware->ReadDigIn(i); Hardware->fPTC[i]=Hardware->ReadPT1000(i); Hardware->bRelais[i]=Hardware->ReadRelais(i); if(i<8){ Hardware->fRDA[i]=Hardware->ReadAnlgIn(i); Hardware->fANG[i]=Hardware->ReadAnlg(i); } } int temp=0; for(int i=0;i<8;i++){ if(HardwareView->CheckListBox1->Checked[i]==true) temp+=pow(2,i); } Hardware->SetRelais(0, temp); temp=0; for(int i=8;i<16;i++){ if(HardwareView->CheckListBox1->Checked[i]==true) temp+=pow(2,(i-8)); } Hardware->SetRelais(1, temp); } else{ for(int i=0;i<16;i++) HardwareView->CheckListBox1->Checked[i]=false; } //HardwareView->Write_Label(); sieht folgendermaßen aus: TEdit* SMTText[16]={Edit1,Edit2,Edit3,Edit4,Edit5,Edit6,Edit7,Edit8,Edit9, Edit10,Edit11,Edit12,Edit13,Edit14,Edit15,Edit16}; TEdit* AInText[8]={Edit17,Edit18,Edit19,Edit20,Edit21,Edit22,Edit23,Edit24}; TEdit* PTText[16]={Edit33,Edit34,Edit35,Edit36,Edit37,Edit38,Edit39,Edit40, Edit41,Edit42,Edit43,Edit44,Edit45,Edit46,Edit47,Edit48}; TLabel* RelaisStatusText[16]={Label82,Label83,Label84,Label85,Label86,Label87, Label88,Label89,Label90,Label91,Label92,Label93, Label94,Label95,Label96,Label97}; TTrackBar* Regler[8]={TrackBar1, TrackBar2, TrackBar3, TrackBar4, TrackBar5, TrackBar6, TrackBar7, TrackBar8}; for(int i=0;i<16;i++){ SMTText[i]->Text=FloatToStr(Hardware->fTMP[i]); PTText[i]->Text=FloatToStr(Hardware->fPTC[i]); RelaisStatusText[i]->Caption=BoolToStr(Hardware->bRelais[i],true); if(i<8){ AInText[i]->Text=FloatToStr(Hardware->fRDA[i]); Hardware->SetAnlgOut(i,Regler[i]->Position); } }nein die Label's werden wie oben stehend aktualisiert, das Problem ist nur, dass er sich bei
*1 teilweise, das heißt nicht bei jedem Programmstart aufhängt und sich auch Code-Guard mit der Fehlermeldung "Attempt to access 1 byte" meldet.
Ich glaub dass es an dem liegt denn dadurch glaub ich führt er den Thread nicht weiter aus, zumindest siehts beim debuggen so aus.
Weiters werden die Label eben nicht aktualisiert, wobei keiner der beiden Thread's ausgeführt wird, obwohl ich im Konstruktor meines Hauptfensters foldendes stehen habe:
CProcess=new ControlProcess(false); CWProcess=new WriteProcess(false); Hardware=new THardware();müsste doch eigentlich so wies mir gezeigt worden ist die Thread's initialisieren.
-
hab gerade eine neue Entdeckung gemacht, wenn ich beim debuggen einen Haltepunkt in die while Schleife im Thread der die Hardware abfragt reingebe, funktioniert das Programm fast, die Label's werden aktualisiert usw. nur kann ich dem Programm jetzt nur noch zu schauen und den Ablauf selber nicht mehr beeinflussen, das heißt ich kann kein Relais mehr setzen o.ä.
bin schlicht weg ratlos,
tom
-
Tom7 schrieb:
bin schlicht weg ratlos,
Die Ratschläge schon gelesen?
-
ja hab ich, hat aber auch nix genutzt der zweite Thread arbeitet trotzdem nicht
-
Hallo Tom7,
hast du die Prioritäten der beiden Thread verändert?
Laufen beide Thread ungebremst in einer While-Schleife?
Hast du die Möglichkeit an deinem Hardware->bCOMPort einen Trigger zu setzen der dir dann den Thread für einen Lesezyklus startet?
Kannst du über einen Timer oder die Wait-Funktion von TEvent den Hardware-Thread mit einer bestimmten Frequenz für einen Lesezyklus starten?Tut mir leid daß ich nur Fragen stelle, aber das fällt mir Momentan ein um eventuell den Fehler einzukreisen. Du schreibs mit einem Haltepunkt in der While-Schleife funktioniert was. Ich glaube es handelt sich um ein zeitliches Problem. Zeigst du die Daten nur in der Oberfläche an oder speicherst du die Messdaten auch auf der Festplatte?
evi48
-
Ja ich noch mal,
frag doch die Messdaten auf Änderungen ab und gib nur die veränderten Werte aus.evi48
-
danke erst mal für deine Hilfe, zu deine Fragen:
hast du die Prioritäten der beiden Thread verändert?
bis jetzt hab ich nicht mal gewusst wie das geht, werd aber gleich in der Hilfe nachlesenLaufen beide Thread ungebremst in einer While-Schleife?
so hätte ich es Anfangs probiert, ist aber nicht gegangen, irgendwie eh logisch, die blockieren sich wahrscheinlich ohne die Prioritäten gegenseitigHast du die Möglichkeit an deinem Hardware->bCOMPort einen Trigger zu setzen der dir dann den Thread für einen Lesezyklus startet?
nein hab ich nicht, denn ich darf an der HW nix als funktionierend annehmen da es ein Programm werden soll dass es dem Techniker ermöglicht die Platine zu testen
Kannst du über einen Timer oder die Wait-Funktion von TEvent den Hardware-Thread mit einer bestimmten Frequenz für einen Lesezyklus starten?
das mit der Frequenz könnte u.U gehen, da die Hardware im vergleich zum Programm am PC eh relativ lahm ist, ist halt nur ein 16Mhz µCTut mir leid daß ich nur Fragen stelle, aber das fällt mir Momentan ein um eventuell den Fehler einzukreisen. Du schreibs mit einem Haltepunkt in der While-Schleife funktioniert was. Ich glaube es handelt sich um ein zeitliches Problem. Zeigst du die Daten nur in der Oberfläche an oder speicherst du die Messdaten auch auf der Festplatte?
dieses Problem konnte ich mittlerweile schon lösen -> ich Dödel hab den Thread vor der Hardware erstellt, kann ja nicht gehn -> war wirklich ein zeitliches Problem, jetzt funkt das aber, auch die Labels werden mittlerweile mit Synchronize erstellt, allerdings folgendermaßen://--------------------------------------------------------------------------- void __fastcall ControlProcess::Execute(){ while(bLoop){ Control(); Synchronize(UpdateLabel); } } //--------------------------------------------------------------------------- void __fastcall ControlProcess::UpdateLabel(void){ HardwareView->Write_Label(); } //---------------------------------------------------------------------------ist halt wieder im gleichen Thread aber wenigstens gehts fehlerfrei, jetzt muss ich nur noch den 2.Thread hinbekommen.
mfg
Tom
-
Ich habe noch mal in meinen Prgrammen gestöbert hier ein kurzez Beispiel für WaitFor von TEvent:
// Der Thread ist aufgebaut als eine Endlosschleife, die durch den // Funktionsaufruf "WaitFor" der Klasse TEvent unterbrochen wird. // Die Schleife wird wieder fortgesetzt, wenn ein Ereignis fuer // "OnStatusExecute" gesetzt wird oder der Timeout abgelaufen ist. OnStatusExecute = new TEvent( NULL, // Zugriffsrechte und Vererbungsmoeglichkeiten false, // automatisch zurueckgesetzen false, // TEvent-Objekt mit rueckgesetztem Signal erzeugen ""); // Name eines Windows-Ereignisobjekts void __fastcall TParallelIO::Execute() { char cMessage[255]; while (!Terminated) { // Endlos-Schleife des Thread // Warten auf das Ereignis. Nach Ablauf von zwei Sekunden wird der // Time-Out ausgelöst. if ((OnStatusExecute->WaitFor (TREADTIMEOUT)) != wrTimeout) { // Fehlermeldung ausgeben sprintf(cMessage, "[TParallelIO::Execute]" " Fehler im Thread Fehler-Nr.: %d", OnStatusExecute->LastError); IOPort->msgErrorExt( ICONTROL_PANEL, IFEHLER, "", cMessage); }else { Synchronize(EinlesenIOPort); // Ereignis bearbeiten } // Ende: if ((OnStatusExecute->WaitFor (TREADTIMEOUT)) // != wrSignaled) } // Ende: while (!Terminated) }evi48
-
genau das ist's ja die ändern sich dauernd, und für die 2 oder 3 die wirklich konstant sind lohnt sich der Aufwand nicht
-
Hallo Tom7,
ja da bin ich mir nicht so sicher, dass sich der Auffwand nicht lohnt. Ich mußte leider in einem Projekt feststellen, dass ich bei einer Anzeigefrequenz von 20Hz Schiffbruch erlitten habe. Bei 10Hz ging es noch so, dass ich auch noch Eingaben machen konnte. Ist sicher auch abhängig vom Prozessor aber die Ausgabe unter Windows kostet leider viel Zeit. Eine Abtastung von 100Hz war kein Problem wenn die Anzeige nicht gewesen wäre.Ist es denn möglich, dass du für die gewonnen Messwerte Grenzwertüberschreitungen (nach unten und nach oben) anzeigst und nur auf wunsch des Benutzers den gemessenen Wert anzeigst so als eine Art Protokoll?
evi48
-
du meinst so eine Art, Hysterese???
Wenn sich der Wert innerhalb einer Grenze bewegt bleibt der gleiche Wert stehen??
-
In meinem Programm das eine Platine testen soll, habe ich zu beginn keinen Thread eingebaut gehabt
Kannst du mir mal genauer erklären, was für eine Platine, welcher Controller
befindet sich darauf,was soll getestet werden, welche Kommunikation findet mit dem PC statt, wie
hoch soll die Samplerate sein.
-
Hallo guten Morgen,
da bin ich wieder.Ich meine mit Grenzwert du hast einen Messwert der sich zum Beispiel in dem Bereich -10 bis +8 bewegen darf. Im einfachsten Fall der Anzeige hast du z.B. ein TPanel welches die Farbe clGreen hat wenn der Messwert in diesen Grenzen liegt außerhalb der Genzen clRed. Zusätzlich hast du ein Label in dem du die Messwerte ausgibst wenn der Benutzer das wünscht z.B. Ausgabe der Werte durch Click auf einen Button.
So wie ich das verstanden habe handelt es sich bei deinem Programm um ein Testtool. Da ist es doch für QM sicher hilfreich zum Abschluß des Test die Messwerte auszudrucken.
evi48
-
Kannst du mir mal genauer erklären, was für eine Platine, welcher Controller
befindet sich darauf,was soll getestet werden, welche Kommunikation findet mit dem PC statt, wie
hoch soll die Samplerate sein.Also, guten Morgen vorerst mal.
Die Platine ist von unserer Firma, genauer gesagt von meinem Vorgänger selbst entwickelt und beherberg einen µC509.
Die Platine hat 16 Relais 16 Digitale Eingäge, 8 Analoge Eingägne, 8 Analoge Ausgänge + nochmal 16 digitale Eingänge.
Das ganze kann über 2 verschiedene Protokolle angesprochen werden die sich in der Syntax komplett voneinander unterscheiden (Protokolle sind auch selbst entwickelt).
Die Kommunikation findet entw. über CAN oder COM statt.Beantwortet das deine Fragen?
-
evi48 schrieb:
Eine Abtastung von 100Hz war kein Problem wenn die Anzeige nicht gewesen wäre.
...weshalb man ja auch Anzeige und Datenspeicher u.U. trennen sollte? (->Model-View-Controller-Modell). Ich denke ja nicht, das du eine 100Hz Update-Frequenz der Anzeige erreichen wolltest oder?
-
evi48 schrieb:
Hallo guten Morgen,
da bin ich wieder.Ich meine mit Grenzwert du hast einen Messwert der sich zum Beispiel in dem Bereich -10 bis +8 bewegen darf. Im einfachsten Fall der Anzeige hast du z.B. ein TPanel welches die Farbe clGreen hat wenn der Messwert in diesen Grenzen liegt außerhalb der Genzen clRed. Zusätzlich hast du ein Label in dem du die Messwerte ausgibst wenn der Benutzer das wünscht z.B. Ausgabe der Werte durch Click auf einen Button.
So wie ich das verstanden habe handelt es sich bei deinem Programm um ein Testtool. Da ist es doch für QM sicher hilfreich zum Abschluß des Test die Messwerte auszudrucken.
evi48
Das mit den Bereichen ist an und für sich eine gute Idee, nur wenn beim Kunden eine Platine eine Fehler hat und diese getestet werden soll, verbinde ich einfach die analog Ausgänge und die analog Eingänge -> ergo Ich weiß durch meine eigene Einstellung was rauskommen muss. Aber das mit dem Protokoll und dem in die Datei speichern wäre viell. keine schlechte Idee
-
Eine Frage hab ich allerdings noch:
Das Programm läuft jetzt, aber eben nur in einem Thread:
void __fastcall ControlProcess::Execute(){ while(bLoop){ Control(); Synchronize(UpdateLabel); } }wenn ich aber nun wie mir gesagt wurde die Prioritäten hinzufüge und 2 Thread's erzeuge funkt's nicht mehr, ich hab das so gelöst:
void Construct_All(void){ Hardware=new THardware(); CProcess=new ControlProcess(true);//Thread erstellen, nicht ausführen WProcess=new WriteProcess(true); CProcess->Priority=tpNormal; //niedrigere Priorität WProcess->Priority=tpLower; CProcess->Resume(); //Thread startet jetzt WProcess->Reusme(); }müsste doch eigentlich stimmen oder?
wenn ich das programm starte tut sich gar nix, es wird zwar der CProcess Thread gestartet aber nicht der WProcess.
-
Hallo Junix,
nein natürlich nicht mit 100Hz anzeigen so schnell kann man sicher nicht kucken. Ich wollte nur sagen, daß das abtasten mit der Frequenz möglich ist.evi48
-
Hallo Tom7,
das sieht für mich so aus als würdest du die While-Schleife mit allem was der PC hergibt durchlaufen.void __fastcall ControlProcess::Execute(){ while(bLoop){ Control(); Synchronize(UpdateLabel); } }Da kann die Anzeige nicht mitkommen und dein Programm läuft nicht. Junix hat mich auch zu diesem Problem in diesem Thread angesprochen. Du mußt die Anzeige von dem Messthread entkoppeln. Soll heissen dein Messthread schreibt die Daten in einen Puffer auf den dein Anzeigethread zugreifen darf (geschützter Bereich), aber mit einer total anderen Frequenz läuft wie dein Messthread.
evi48