Warterei in einen Thread auslagern

Für Fragen zur Programmiersprache auf welcher Lazarus aufbaut
haderlump
Beiträge: 185
Registriert: Fr 18. Jan 2013, 09:29
OS, Lazarus, FPC: Windows 10, Windows XP, Lazarus 1.6
CPU-Target: Celeron

Re: Warterei in einen Thread auslagern

Beitrag von haderlump »

So, liebe Leute
Ich möchte mich nun aktiv aus diesem Tread ausklinken und bedanke mich herzlich für euer Engagement.
Ich habe wieder viel dazugelernt, und habe dabei entdeckt, dass das was ich vorhatte aus anderen Gründen nicht realisierbar ist. Ich werde nun brav warten bis der Aufzug an Ort und Stelle ist. Die halbe Minute geht auch vorbei :roll:

Herzlich Grüße
Fritz

Christian
Beiträge: 6079
Registriert: Do 21. Sep 2006, 07:51
OS, Lazarus, FPC: iWinux (L 1.x.xy FPC 2.y.z)
CPU-Target: AVR,ARM,x86(-64)
Wohnort: Dessau
Kontaktdaten:

Re: Warterei in einen Thread auslagern

Beitrag von Christian »

Also in nem Thread hat man einen Aufrufstack und kann genau nachvollziehen von wo man auf welchem Weg gekommen ist. Bei State Mashines hab ich immer das Problem das mi genau das fehlt. Man hat zwar den aktuellen Zustand aber weiss nie wie es dazu gekommen ist. Das kann man zwar loggen, dann muss man sich aber erstmal durch tonnen Logs der anderen Threads wühlen.
Mich würden gerade Martins Erfahrungen mal interessieren.
W.m.k.A.h.e.m.F.h. -> http://www.gidf.de/

haderlump
Beiträge: 185
Registriert: Fr 18. Jan 2013, 09:29
OS, Lazarus, FPC: Windows 10, Windows XP, Lazarus 1.6
CPU-Target: Celeron

Re: Warterei in einen Thread auslagern

Beitrag von haderlump »

Ich muss mal wieder auf diesen Beitrag zurückkommen.
Ich habe nun einen eigenen thread programmiert. Dieser soll sich um die Kontaktabfrage kümmern.
Die Kontakte sind in der Anlage an Microcontroller angeschlossen. Bei Kontaktveränderung senden diese ein Telegramm über die serielle Schnittstelle an den PC.
Geht auch alles gut.
Nun habe ich diese Auswertung in einen eigenen thread gepackt. Dieser funktioniert auch - solange das Hauptprogramm nichts macht.

Das weiter oben beschriebene Problem tritt auch bei meiner Segmentdrehscheibe auf.
Ich habe mir das folgendermaßen gedacht: Das Hauptprogramm veranlass die Drehscheibe zum umlaufen. Ok. das klappt.
Nun muss es aber warten bis dieser Umlauf abgeschlossen ist.
Die Drehscheibe gibt bei Umlaufende ein Telegramm über den MC dass die Bewegung abgeschlossen ist. Das Signal kommt auch am PC an. (mit HTerminal geprüft).
Nun wieder zum Hauptthread:
Dazu habe ich eine while- schleife geschrieben.

Code: Alles auswählen

 
while not akt_element^.busy  do;
//weiterer Programmcode
 

Dieses busy-Kriterium soll vom Kontakt-Thread auf false gesetzt werden.
Solange der Kontaktthread alleine läuft geht alles wunderbar, aber sobald ich in die while-Anweisung komme (ein sleep-Befehl bewirkt übrigens das Gleiche) , schein der Kontaktthread blockiert zu sein.
Ich habe im Kontaktthread ein paar Meldungen installiert, diese funktionieren plötzlich auch nicht mehr. Im Thread-Kontrollfenster von Lazarus steht aber bei beiden threads: "running".
Übrigens: der Kontaktthread muss immer laufen, denn auch die Gleisfreimeldung läuft über diesen.

Vielleicht könnt ihr mir helfen?

Gruß Fritz

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: Warterei in einen Thread auslagern

Beitrag von mschnell »

"Busy wait" Schleifen sind immer schlecht, weil sie ja andere Threads am Arbeiten hindern.

Deshalb muss man sicherstellen, dass sie nie länger als eine sehr kurze Zeitspanne warten.

Im Main-Thread ist "busy wait" grundsätzlich verboten. Im Worker Thread ist es manchmal nicht zu vermeiden. In diesem Fall muss man überlegen ob man mit sleep() anderen Threads die Möglichkeit geben kann, etwas sinnvolles zu tun.

Im MainThread ist sleep wiederum auch verboten (weil dann keine Ereignisse mehr abgearbeitet werden). Im Worker-Thread erhöht sleep die Latenz um so mehr je länger der sleep angefordert wird, umgekert behindert man mit einem kürzerer sleep die anderen Threads (und parallel laufende Programme) stärker als mit einem längeren. Das muss dann abgewogen werden.

Es gibt divere Möglichkeiten von einem Worker Thread dem Mainthread Mitteilungen zu machen ("Events auslösen"), so dass der nicht pollen muss: TThread.Synchronize, TThread.Queue, TThread.Waitfor, TEvent, Application.QueuAsyncCall, ...

-Michael

haderlump
Beiträge: 185
Registriert: Fr 18. Jan 2013, 09:29
OS, Lazarus, FPC: Windows 10, Windows XP, Lazarus 1.6
CPU-Target: Celeron

Re: Warterei in einen Thread auslagern

Beitrag von haderlump »

Danke Michael
Mein Problem ist nun gelöst. Ich habe dem Programmteil in dem die Warteschleife vorkommt in einen eigenen Thread spendiert. In die Warteschleife habe ich einen sleep mit 5 ms eingebaut.
Alles läuft jetzt wie geschmiert.
Allerdings musste ich den Datenzugriff umstrukturieren und so gibt es noch ein paar Kleinigkeiten auszutesten und zu korrigieren. Aber das ist kein Problemm mehr.

Gruß Fritz

P.S.
Ganz allgemein möchte ich mich hier noch bei all den fleissigen Helferlein bedanken, die sich die Mühe machen, die Beiträge hier zu lesen und uns Laien mit guten Ratschlägen und Lösungen zu helfen.
Leider kann ich mich wegen meiner bescheidenen Kenntnisse nicht revanchieren.

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: Warterei in einen Thread auslagern

Beitrag von mschnell »

Wie gesagt ist sleep im MainThread verboten, weil die GUI dadurch schlecht funktioniert, und im Worker Thread unschön, aber manchmal schlecht zu vermeiden.
Aber wenn Deine Lösung für Dich funktioniert und Du keine Arbeit in eine Perfektionierung investieren willst, weil dieses und zukünftige Projekte es nicht rechtfertigt, ist das natürlich OK.

-Michael

haderlump
Beiträge: 185
Registriert: Fr 18. Jan 2013, 09:29
OS, Lazarus, FPC: Windows 10, Windows XP, Lazarus 1.6
CPU-Target: Celeron

Re: Warterei in einen Thread auslagern

Beitrag von haderlump »

Hallo zusammen
So, nun hab ich das nächste Problem.
In einer bestimmtn Situation muss ich ein Formular öffnen.
Ich hatte das erst normal geöffnet, das ging auch. Nun muss ich aber dort einen Eingabe vornehmen, deshalb möchte ich es modal öffnen.
Jetzt kommt allerdings eine Exeption mit der Meldung "Formular wurde nicht aus dem mainthread geöffnet" oder sinngemäß.
Jetzt stehe ich wieder auf dem Schlauch. Gibt es da irgend eine Formulareigenschaft, die falsch steht, oder geht das generell nicht.

Gruß Fritz

Michl
Beiträge: 2505
Registriert: Di 19. Jun 2012, 12:54

Re: Warterei in einen Thread auslagern

Beitrag von Michl »

haderlump hat geschrieben:Jetzt kommt allerdings eine Exeption mit der Meldung "Formular wurde nicht aus dem mainthread geöffnet" oder sinngemäß.
Das ist richtig. Nur Mainthread ist im OS für die Formularverwaltung registriert. Daher dürfen auch nur von diesem aus Zugriffe auf Formulare durchgeführt werden.

Du könntest per Synchronize eine Procedure im Mainthread aufrufen, die das Formular modal öffnet. Den Workerthread könntest mittels RTLEventWaitFor (möglichst mit TimeOut) warten lassen. Wenn das modale Fenster geschlossen wird, kannst du das RTLEvent feuern. Daten, die vom Mainthread und Workerthread gelesen und verändert werden können, müssen geschützt werden, daß nicht zur gleichen Zeit ein lesender und schreibender Zugriff erfolgt, z.B. per TRTLCriticalSection.

Code: Alles auswählen

type
  TLiveSelection = (lsMoney, lsChilds, lsTime);
  TLive = Array[0..1] of TLiveSelection; 

Antworten