Thread mit Timer
-
ih möchte Threads verwenden, habe damit aber so meine Probleme. In diesem Zusammenhang habe ich flg Code bekommen:
int i=0; LONGLONG lpFrequency, alt, neu; __fastcall MeinThread::MeinThread(bool CreateSuspended): TThread(CreateSuspended) { //Prozessorgeschwindigkeit ermitteln QueryPerformanceFrequency((LARGE_INTEGER*)&lpFrequency); Priority = tpHighest; } //--------------------------------------------------------------------------- void __fastcall MeinThread::Execute() { //Startzeit ermitteln QueryPerformanceCounter((LARGE_INTEGER*)&alt); while(!Terminated) /* Die Eigenschaft Terminated zeigt an, ob der Thread eine Aufforderung zum Beenden erhalten hat */ { QueryPerformanceCounter((LARGE_INTEGER*)&neu); if((neu-alt)/(double)lpFrequency >= (0.1*i)){ Synchronize(UpdateCaption); } Sleep(1); } Form1->lAnzeige->Caption = "beendet"; } //--------------------------------------------------------------------------- void __fastcall MeinThread::UpdateCaption() { Form1->lAnzeige->Caption = i++; }
Unit1:
MeinThread* thread = new MeinThread(true); void __fastcall TForm1::LMDButton1Click(TObject *Sender) { thread->Resume(); /* Die Methode Resume setzt die Ausführung eines unterbrochenen Threads fort */ } //--------------------------------------------------------------------------- void __fastcall TForm1::LMDButton2Click(TObject *Sender) { thread->Suspend(); /* Die Methode Suspend unterbricht die Ausführung eines Threads */ } //--------------------------------------------------------------------------- void __fastcall TForm1::LMDButton3Click(TObject *Sender) { thread->Terminate(); /* Die Methode Terminate signalisiert die Beendigung eines Threads. Dazu wird die Eigenschaft Terminated auf true gesetzt. */ }
Ich will damit mehrere Sensoren auslesen, die den Wert in einer einstellbaren Zeit aktualisieren. Das funktioniert mit diesem Code. Habe diesen allerdings noch nicht ganz verstanden. Wie der Timer an sich funktioniert weiss ich auch. Nur die Sache mit dem synchonize will mir nicht in den Kopf und die Zeile
if((neu-alt)/(double)lpFrequency >= (0.1*i)){ Synchronize(UpdateCaption); } Sleep(1
)
ich hoffe ihr könnt mir da weiterhelfen.
-
Hallo
Synchronize ist dafür da, das der Thread mit Elementen außerhalb seines Wirkungsbereiches arbeiten kann. Im allgemeinen benutzt man es, um den Status der Threadverarbeitung in GUI-Controls anzuzeigen. Denn die GUI läuft in ihrem eigenem Thread.
Mehr zu TThread und ::Synchronize findest du im Tutorial.bis bald
akari
-
ich fass mal zusammen wie ich das verstanden hab:
- im Konstruktor wird die Taktfrequenz der CPU ermittelt und die Adresse dieses Werts in dem Zeiger lpFrequency gespeichert. Ausserdem wird die Priorität des Threads erhöht (tpHighest)
- in der Methode Execute wird der aktuelle Stand (Takt)der CPU abgefragt und die Adresse davon im Zeiger alt gespeichert, die while Schleife führt den im Block stehenden Code solange aus bis die Eigenschaft Terminated auf true gesetzt wird. Dabei wird wieder der aktuelle CPU-Takt aufgenommen und in der Variable neu gespeichert. In der if-Abfrage wird geprüft ob die gemessene Zeit (Differenz alt, neu geteilt durch die Frequenz) größer oder gleich 0.1 * i ist.
wenn nicht wartet die CPU eine Sekunde.Das versteh ich jetzt nicht mit dem Timer. Die angegebene Hilfe bringt mir da leider auch nichts, da es dort anders gemacht wurde.
-
Hallo
Ich hab erstmal den Link in meinem letzten Post korrigiert, der hat gefehlt.
Was verstehst du nicht an Thread? Falls es noch um Synchronize geht :
1. Du darfst aus einem Thread normalerweise heraus nicht auf Speicher zugreifen, der nicht zu dem Thread gehört. Dazu gehören auch alle GUI-Komponenten
2. Also werden alle GUI-Zugriffe in eine extra Methode ausgelagert, bei dir UpdateCaption
3. Diese Funktion darf aber nicht direkt von TThread::Execute aus aufgerufen werden, sondern muß als Funktionszeiger an die Methode Synchronize übergeben werden.
4. Synchronize sorgt dafür, das vor dem Ausrühren von UpdateCaption erst der Thread mit dem GUI-Thread synchroniziert wird. Dann ist der Zugriff innerhalb von UpdateCaption auf GUI-Komponenten erlaubt.bis bald
akari
-
ok das hab ich dann denk ich kapiert, dh. ich muss alles was mit der GUI zu tun hat, ZB Ausgabe eines Messwerts auf ein Label, in eine extra Funktion schreiben, hier UpdateCaption. Der primäre Thread wird also während der Ausführung vorübergehend angehalten. ok, das ist klar.
Was soll dann aber die Zeile:
if((neu-alt)/(double)lpFrequency >= (0.1*i)){
Versteh den zusammenhang mit dem Timer nicht
den Code hatte ich von einem Kollegen.
Es geht am Ende darum einene Messwert auszulesen, der von einem Sensor kommt. Das alles soll in einem Thread verpackt werden. Die Ansteuerung des Sensors sowie die Einstellung der verschiedenen Parameter dieses Sensors funktioniert bereits.
-
Hallo
Ist doch eigentlich eine nachvollziehbare Berechnung :
Mit QueryPerformanceFrequency wird vom Betriebssystem der aktuelle Zeitstempel geholt und in neu gespeichert. Aus der Differenz zu alt (dem ersten Zeitstempel, bei dem etwas ausgegeben wurde) ergibt sich der Zeitraum, der seit der letzten Aktualisierung der GUI vergangen ist. Dieser wird nun in (Milli-) Sekunden umgerechnet und dann mit der eingestellten Frequenz verglichen. Ist ein Frequenz-Intervall vorbei, wird die GUI aktualisiert.Anmerkungen :
- Das i, lpFrequency, alt, neu offenbar globale Variablen sind, ist äußerst schlecht. Es sollten Member-Variablen deiner Thread-Klasse seinbis bald
akari
-
Außerdem mußt du für die Zeile
Form1->lAnzeige->Caption = "beendet";
auch den Synchronize-Mechanismus benutzen.
Desweiteren ist es schlecht, daß du direkt auf Form1 und dessen Controls zugreifst - so koppelst du den Thread zu stark an die Form1.
-
wie macht man das denn anders bzw besser? mir wurde es so gezeigt
-
Hallo
Du erstellst eine zweite Update-Methoden und verlegst den "beendet"-Aufruf darein.
In der Execute-Methode rufst du dann Synchronize mit dieser zweiten Update-Methode aufbis bald
akari
-
Ein sleep(1) kehrt nicht nach 1 ms wie erwartet zurück! Meistens viel später, weil die Windows-API das gleiche Problem mit den Ungenauigkeiten hat. Du kannst ja spassenshalber einmal 500 mal messen wie lange denn das sleep(1) gedauert hat. Es ist enttäuschend!
MfG
-
Ich habe mal die Sleep-Funktionen getestet und dabei folgendes Kurioses festgestellt:
Sleep(n) | Anzahl/Sekunde (Durchschnitt über mehrere Sekunden) -------------------------------------------------------------- 0 | ca. 800.000 1 | 500 2 | 333 3 | 250 4 | 200 5 | 167 10 | 91 100 | 9.9
Wie man sieht, scheint der Sleep() intern um 1 ms höher zu sein, als man angegeben hat (nur bei 0 ist es korrekt)!
-
Ich glaube eher, dass der Rest deines funktionalen Codes die 'fehlenden' Counts erklärt.
Gruß KK