TThread.Suspend Alternative

Antworten
Nimral
Beiträge: 390
Registriert: Mi 10. Jun 2015, 11:33

TThread.Suspend Alternative

Beitrag von Nimral »

Hi allseits,

ich habe in Multitasking-Programm, das unter Windows prima funktioniert. Es liest mit einem Thread ein serielles Meßgerät aus, und übergibt die Messwerte an eine GUI, mit der man die Parameter der Messvorgänge steuern kann. Mit der GUI kommuniziere ich über Synchronize. Gut.

Nun bringt es die Anwendung mit sich, dass ich den Task von der GUI aus auf Knopfdruck hin und wieder für eine Weile anhalten muss. Wenn die Messwerte zu sehr aus dem Ruder laufen, merkt das die GUI, und der Anwender muss nun was tun und das auf der GUI quittieren. Wenn das Messgerät neu kalibriert wird, darf der Auslese-Thread auf keinen Fall weiter laufen. Das hat unter Windows ganz gut geklappt über die Suspend und Resume Methoden von TThread, der Compiler hat zwar immer fürchterlich gemeckert dass das böse, böse, böse und deshalb deprechated sei, aber gelaufen ist das Programm trotzdem.

Jetzt wollte ich das Programm unter Linux auf einem Raspi verwenden, und das Multithreading funktioniert auf Anhieb - bis auf die Suspend und Resume Geschichte. Unter Linux weigert sich der Compiler, das Programm überhaupt zu übersetzen: "Suspending one thread from inside another one is unsupported (...)".

Ich muss jetzt also in den sauren Apfel beißen und nach der "sauberen" Alternative suchen. Einige hemdsärmelige Ideen habe ich natürlich, z.B. die "while not terminated" Schleife in der execute Methode von TThread mit einem "Suspended:boolean" Flag leer durchlaufen lassen. Ist das wirklich eine gute Idee, oder belastet mir die leere Schleife nicht den Prozessor unnötig, und wenn ja, wie kann ich das vermeiden (ein Sleep mit dazu nehmen?).

Wer hat mir Tipps, wie ich den Thread elegant steuern kann, so dass das unter Windows und unter Linux funktioniert?

Thx, Armin.

Socke
Lazarusforum e. V.
Beiträge: 3158
Registriert: Di 22. Jul 2008, 19:27
OS, Lazarus, FPC: Lazarus: SVN; FPC: svn; Win 10/Linux/Raspbian/openSUSE
CPU-Target: 32bit x86 armhf
Wohnort: Köln
Kontaktdaten:

Re: TThread.Suspend Alternative

Beitrag von Socke »

Die saubere Alterntive sind Events: https://wiki.lazarus.freepascal.org/Mul ... her_thread
Der Ablauf wäre wohl wie folgt:
  1. Die GUI signalisiert dem Thread, zu warten (z.B. per Variable)
  2. Der Thread wertet die Variable aus und wartet auf das Event
  3. Sobald die Kalibrierung fertig ist, setzt die GUI das Event und der Thread läuft weiter
MfG Socke
Ein Gedicht braucht keinen Reim//Ich pack’ hier trotzdem einen rein

mschnell
Beiträge: 3444
Registriert: Mo 11. Sep 2006, 10:24
OS, Lazarus, FPC: svn (Window32, Linux x64, Linux ARM (QNAP) (cross+nativ)
CPU-Target: X32 / X64 / ARMv5
Wohnort: Krefeld

Re: TThread.Suspend Alternative

Beitrag von mschnell »

Der Thread läuft ja anscheinend zyklisch.
Reicht es nicht, wenn er einfach in jedem Zyklus eine von der GUI gesetzte Variable variable liest und während der Auszeit die Messergebnisse nicht erfasst oder verwirft ?
-Michael

Nimral
Beiträge: 390
Registriert: Mi 10. Jun 2015, 11:33

Re: TThread.Suspend Alternative

Beitrag von Nimral »

mschnell hat geschrieben:Der Thread läuft ja anscheinend zyklisch.
Reicht es nicht, wenn er einfach in jedem Zyklus eine von der GUI gesetzte Variable variable liest und während der Auszeit die Messergebnisse nicht erfasst oder verwirft ?
-Michael


Ja, das würde vermutlich reichen. Ich habs ja in der Frage bereits skizziert, z.B. mit einer Variable

while not Terminated do
begin
...

while ThreadSuspended() do
begin
sleep(500);
end;
end;

ThreadSuspended würde auf eine Variable zurückgreifen, die von der GUI aus gesetzt und rückgesetzt werden kann --> nach jedem gelesenen Wert bekommt die GUI die Chance, den Thread anzuhalten.

Ist halt ein bisschen hemdsärmelig, hat allerdings auch seine Vorteile, z.B. dass der Thread immer an einer Stelle gestoppt werden kann wo das Stoppen sicher keine unliebsamen Nebenwirkungen hat. Es wäre auch sicher sinnvoll, In ThreadSuspended() eine Variable zu setzen damit die GUI weiß, dass sich der Thread in seiner Warteschleife befindet und sie ihrerseits weiter machen kann.

Events wären natürlich auch möglich, Die GUI könnte dem Thread einen senden um ihn in die Warteschleife zu schicken, wenn der Thread in die Warteschleife eintritt könnte er einen generieren um der GUI anzuzeigen dass sie jetzt dran ist, und wenn die GUI ihrerseits fertig ist könnte sie dem Thread ein Event schicken damit er die Warteschleife wieder verlässt.

Gibt es Gründe, die Event-Methode, die ich als aufwändiger empfinde, zu bevorzugen?

Und ist das wirklich *alles* was den Machern zum Thema Thread anhalten eingefallen ist? Da gibt es andere Sprachen wo man die nicht anhaltefähigen Codeteile markiert ("CriticalSection"), und den Rest des Codes kann man nach Belieben stoppen und starten.

HG, Armin.

mschnell
Beiträge: 3444
Registriert: Mo 11. Sep 2006, 10:24
OS, Lazarus, FPC: svn (Window32, Linux x64, Linux ARM (QNAP) (cross+nativ)
CPU-Target: X32 / X64 / ARMv5
Wohnort: Krefeld

Re: TThread.Suspend Alternative

Beitrag von mschnell »

"while ThreadSuspended() do begin sleep(500); end; end"
Das geht, busy polling ist aber nie schön - ich empfinde es immer als unsauber. Wenn der Thred tatsächlich nichts tun soll, kann man dann besser eine Semphore (TThread.CriticalSection) verwenden. Wenn der Thread noch etwas tun muss, geht das natürlich nicht so.
Nimral hat geschrieben:den Rest des Codes kann man nach Belieben stoppen und starten.

Hört sich ziemlich unsinnig an.
-Michael
Zuletzt geändert von mschnell am Do 16. Jan 2020, 10:18, insgesamt 3-mal geändert.

Socke
Lazarusforum e. V.
Beiträge: 3158
Registriert: Di 22. Jul 2008, 19:27
OS, Lazarus, FPC: Lazarus: SVN; FPC: svn; Win 10/Linux/Raspbian/openSUSE
CPU-Target: 32bit x86 armhf
Wohnort: Köln
Kontaktdaten:

Re: TThread.Suspend Alternative

Beitrag von Socke »

Nimral hat geschrieben:Da gibt es andere Sprachen wo man die nicht anhaltefähigen Codeteile markiert ("CriticalSection"), und den Rest des Codes kann man nach Belieben stoppen und starten.


Es geht ja gerade darum, einen Thread nicht anzuhalten, während er sich innerhalb einer Critical Section befindet.
In Programmiersprachen die keinen Maschinencode erzeugen, kann man das von Außen nicht zuverlässig feststellen.

Was aber geht: du kannst es in deinem Thread zuverlässig erkennen. Dort kannst du die von der GUI gesetzte Variable abfragen und Suspend aufrufen.
Schau dir hierzu einfach mal die Implementierung von TThread.Suspend unter Linux an. Dort werden die von mir erwähnten Events genutzt; du musst die Events also gar nicht mehr selbst implementieren - nur die Suspend-Aufruf von der GUI in den Thread verlagern.
MfG Socke
Ein Gedicht braucht keinen Reim//Ich pack’ hier trotzdem einen rein

Antworten