Wann Brauche ich Synchronize

Für Fragen von Einsteigern und Programmieranfängern...
Lomat
Beiträge: 28
Registriert: Fr 14. Jan 2022, 13:44

Wann Brauche ich Synchronize

Beitrag von Lomat »

Hallo,

ich habe mal eine Frage, weil ich mir nicht sicher bin, warum meine Anwendung überhaupt funktioniert. Ich bin mal ganz frech hingegangen und habe das Laden (LoadFromCSVFile) und Speichern (SaveToCSVFile) von Dateien über ein StringGrid in einen Thread ausgelagert. Nebeibei aktualsisiere ich Graphen in der Chart-Komponente und einen Fortschrittbalken (ProgressBar). Vor dem Vorgang setze ich diverse Oberflächenelemente auf disabled (Synchronize(@DisableSurface)) bzw. danach auf enabled (Synchronize(@EnableSurface)). Das sind die einzigen Funktionen, bei denen ich Syncronize verwende. Ich habe gehört, man soll in Threads nicht auf der Oberfläche herumklimpern. Was kann da eigentlich schiefgehen und warum passiert es nicht bei mir?

Sinn der Übung ist es, dass sich der Prozess auch über die Escape-Taste bzw. den nicht gesperrten Abbruchknopf abbrechen lässt, falls es zu lange dauert. Exakt das funktioniert auch. Zufall?

Viele Grüße

Christoph

Warf
Beiträge: 1908
Registriert: Di 23. Sep 2014, 17:46
OS, Lazarus, FPC: Win10 | Linux
CPU-Target: x86_64

Re: Wann Brauche ich Synchronize

Beitrag von Warf »

Nur der main thread darf auf die Oberfläche zugreifen, weil die GUI Frameworks wie WinAPI oder QT einfach nicht threadsafe sind und es einfach komplett verbieten.

Generell als Faustregel, du benötigst eine Form der Synchronisation (critical sections, events, synchronize, TThread.Queue) immer wenn du auf geteilte nicht thread sichere Datenstrukturen zugreift. Das sind all die Datenstrukturen bei denen nicht explizit dokumentiert sind das sie thread safe sind (also I'm Grunde fast alles)

Allerdings solltest du synchronize falls möglich vermeiden da es beide threads (Arbeiter und main) blockiert während der ganzen Synchronisation. Benutz lieber TThread.Queue

Lomat
Beiträge: 28
Registriert: Fr 14. Jan 2022, 13:44

Re: Wann Brauche ich Synchronize

Beitrag von Lomat »

Hallo,

ja das mit den geteilten Datenstrukturen ist mir klar.

Ist es richtig, dass synchronize bewirkt, dass der Thread, in dem synchronize ausgeführt wird stoppt und der Hauptthread dann alles bis zur synchronisierten Procedure abarbeitet, damit anschließend der Thread weiter arbeiten kann? Dann tut synchronize an den zwei Stellen, an den ich es verwendet habe genau das richtige. Ich denke aber, ich muss noch weitere Sachen an besten über Queue absichern.

Was mir nicht ganz klar ist: Wenn ich das StringGrid in dem Thread erzeuge und auch nach Verwendung wieder zerstöre, hat es dann überhaupt was mit dem Hauptthread zu tun? Ich brauche es zunächst nur als Datenkontainer und für die die bequeme Möglichkeit eine csv-Datei zu laden und zu speichern. Das was der Hauptthread zu tun hat ist im wesentlichen Graphen für ein TChart-Objekt anzunehmen und den Fortschrittbalken zu aktualiseren, sowie dem Thread, der gerade liest / schreibt zu signalisieren, dass der Benutzer den Vorgang abbrechen möchte. Schön wäre noch die Aktualiserierung eines Stringgrids zur Anzeige aktueller Daten. Wie gesagt, alles das funktioniert sogar. Was nicht funktionierte und mit einem Absturz endete, war der versehntliche Versuch, den Laden-Dialog zu starten....ist halt beim Umkopieren des Codes in den Thread versehenlich da gelandet.

Viele Grüße

Christoph

Benutzeravatar
af0815
Lazarusforum e. V.
Beiträge: 6198
Registriert: So 7. Jan 2007, 10:20
OS, Lazarus, FPC: FPC fixes Lazarus fixes per fpcupdeluxe (win,linux,raspi)
CPU-Target: 32Bit (64Bit)
Wohnort: Burgenland
Kontaktdaten:

Re: Wann Brauche ich Synchronize

Beitrag von af0815 »

Lomat hat geschrieben:
So 12. Feb 2023, 01:22
Ist es richtig, dass synchronize bewirkt, dass der Thread, in dem synchronize ausgeführt wird stoppt und der Hauptthread dann alles bis zur synchronisierten Procedure abarbeitet, damit anschließend der Thread weiter arbeiten kann?
Genau dann, wenn es so ist, wie du schreibst brauchst du keinen Thread, weil gegenseitig gestoppt wird.

Der Thread und das Hauptprogramm sollten komplett voneinander unabhängig sein, dann kann jeder seine Arbeit machen und du nutzt alles aus. Das heisst, wenn der Thread was zum Anzeigen hat, so hat er das abzulegen, den Hautpthread davon zu verständigen. Bis der Hauptthread das erledigt hat, kann er ja weitermachen. Und der Hauptthread zeigt das an, was er gerade vorgefunden hat.
Blöd kann man ruhig sein, nur zu Helfen muss man sich wissen (oder nachsehen in LazInfos/LazSnippets).

Warf
Beiträge: 1908
Registriert: Di 23. Sep 2014, 17:46
OS, Lazarus, FPC: Win10 | Linux
CPU-Target: x86_64

Re: Wann Brauche ich Synchronize

Beitrag von Warf »

Lomat hat geschrieben:
So 12. Feb 2023, 01:22
Ist es richtig, dass synchronize bewirkt, dass der Thread, in dem synchronize ausgeführt wird stoppt und der Hauptthread dann alles bis zur synchronisierten Procedure abarbeitet, damit anschließend der Thread weiter arbeiten kann? Dann tut synchronize an den zwei Stellen, an den ich es verwendet habe genau das richtige. Ich denke aber, ich muss noch weitere Sachen an besten über Queue absichern.

Was mir nicht ganz klar ist: Wenn ich das StringGrid in dem Thread erzeuge und auch nach Verwendung wieder zerstöre, hat es dann überhaupt was mit dem Hauptthread zu tun?
Deine Beschreibung oben klingt für mich als wäre application.processmessages vermutlich ausreichend um die ausstehenden events abzuarbeiten.

Bezüglich dem StringGrid, das Problem ist das jede GUI Komponente Aufrufe zur unterliegenden GUI Bibliothek macht. Welche genau kann man nicht pauschal sagen, da das durch das widgetset und die LCL abstrahiert wird. Aber wenn die GUI Bibliothek nicht threadsicher ist, sind die calls auch nicht möglich. Selbst wenn alle Funktionalität die du benutzt rein Teil der LCL Datenstrukturen sind und du eigentlich keine der unterliegenden WS Funktionalitäten bräuchtest

Benutzeravatar
theo
Beiträge: 10467
Registriert: Mo 11. Sep 2006, 19:01

Re: Wann Brauche ich Synchronize

Beitrag von theo »

Lomat hat geschrieben:
Sa 11. Feb 2023, 18:01
habe das Laden (LoadFromCSVFile) und Speichern (SaveToCSVFile) von Dateien über ein StringGrid in einen Thread ausgelagert.
Wieso hast du das überhaupt gemacht?
War das so langsam auf deinem Rechner, dass es andere Aktionen verhindert/blockiert hat?
Wie viele Einträge hat denn der StringGrid?
Aus meiner Erfahrung sollte man separate Threads nur dann verwenden, wenn es richtig gute Gründe dafür gibt und man genau weiss, was man tut.
Das Leben und das Debugging wird nicht einfacher durch separate Threads.

Benutzeravatar
theo
Beiträge: 10467
Registriert: Mo 11. Sep 2006, 19:01

Re: Wann Brauche ich Synchronize

Beitrag von theo »

Lomat hat geschrieben:
So 12. Feb 2023, 01:22
Ich brauche es zunächst nur als Datenkontainer und für die die bequeme Möglichkeit eine csv-Datei zu laden und zu speichern.
Dafür gibt es TCsvDocument:
https://wiki.freepascal.org/CsvDocument
https://www.freepascal.org/daily/doc/fc ... ument.html

Lomat
Beiträge: 28
Registriert: Fr 14. Jan 2022, 13:44

Re: Wann Brauche ich Synchronize

Beitrag von Lomat »

Hallo nochmal, Danke für die Antworten,

ich habe festgestellt, dass mein Vorgehen so lange gut geht, solange keine Interaktion des Benutzers mit der Oberfläche stattfindet. Das ist mir zu heikel, da Zugriffsverletzungen auftreten, wenn dies doch mal geschieht. Ich versuche mich gerade an einer anderen Lösung.

Mal nebenbei bemerkt. Ich habe einen anderen Prozess, den ich auch in einen Thread ausgelagert habe. Der enthält ein Fenster und einen Timer, sowie eine laut den Erstellern threadsicher RS232-Komponente. Besaget visulle Komponenten sind aber vollkommen losgelöst vom Hauptfenter / Hauptthread, sondern werden im 2. Thread erzeugt und auch wieder freigegeben. Das Ding läuft autarg und hat eine Datenschnittstelle und eine Variable, die anzeigt, ob die gewünschten Daten angekommen sind. Weder Hauptthread noch dieser Thread interagieren mit irgenwelchen Oberflächenkomponenten. Synchronize und Queue sind hier Funtionen, über die ich nicht mal ansatzweise nachdenken musste. Bis jetzt habe ich den Eindruck, dass hier anders als in dem Fall, mit dem ich eröffnet habe, die Stabilität des Programmes profitiert hat und es nicht mehr zu seltsamen Effekten bei der Datenübertragung kommt. Kann es hierbei auch böse Überraschungen geben?

Viele Grüße

Christoph

Benutzeravatar
theo
Beiträge: 10467
Registriert: Mo 11. Sep 2006, 19:01

Re: Wann Brauche ich Synchronize

Beitrag von theo »

Lomat hat geschrieben:
Di 14. Feb 2023, 09:35
Mal nebenbei bemerkt. Ich habe einen anderen Prozess, den ich auch in einen Thread ausgelagert habe. Der enthält ein Fenster und einen Timer, sowie eine laut den Erstellern threadsicher RS232-Komponente. Besaget visulle Komponenten sind aber vollkommen losgelöst vom Hauptfenter / Hauptthread, sondern werden im 2. Thread erzeugt und auch wieder freigegeben.
Soweit ich das verstehe, hat man den Haupthread drin, sobald man eine TForm ein TBitmap etc. benutzt. Jedenfalls auf Linux.
Was du beschreibst ('vollkommen losgelöst'), gibt es meines Wissens gar nicht beim GUI.
Wie gesagt, vergiss die separaten Threads für so etwas (GUI) und benutze sie nur, wenn du die Problematik verstanden hast.
Threads sind kein Spielzeug. :lol:

https://wiki.lazarus.freepascal.org/Mul ... n_Tutorial

Benutzeravatar
af0815
Lazarusforum e. V.
Beiträge: 6198
Registriert: So 7. Jan 2007, 10:20
OS, Lazarus, FPC: FPC fixes Lazarus fixes per fpcupdeluxe (win,linux,raspi)
CPU-Target: 32Bit (64Bit)
Wohnort: Burgenland
Kontaktdaten:

Re: Wann Brauche ich Synchronize

Beitrag von af0815 »

Lomat hat geschrieben:
Di 14. Feb 2023, 09:35
Mal nebenbei bemerkt. Ich habe einen anderen Prozess, den ich auch in einen Thread ausgelagert habe. Der enthält ein Fenster und einen Timer, sowie eine laut den Erstellern threadsicher RS232-Komponente.
Wenn die so TopSecret ist, können wir nicht sagen ob das passt. Eventuell verräts du und, welche Komponente es ist. Und ja es gibt da einige RS232 Komponenten die den blockierenden Teil auch in einen Thread ausgelagert haben.
Blöd kann man ruhig sein, nur zu Helfen muss man sich wissen (oder nachsehen in LazInfos/LazSnippets).

Lomat
Beiträge: 28
Registriert: Fr 14. Jan 2022, 13:44

Re: Wann Brauche ich Synchronize

Beitrag von Lomat »

Hallo, es ist die DataPort-Komponenten von Sergey Bodrov.

Lomat
Beiträge: 28
Registriert: Fr 14. Jan 2022, 13:44

Re: Wann Brauche ich Synchronize

Beitrag von Lomat »


Benutzeravatar
af0815
Lazarusforum e. V.
Beiträge: 6198
Registriert: So 7. Jan 2007, 10:20
OS, Lazarus, FPC: FPC fixes Lazarus fixes per fpcupdeluxe (win,linux,raspi)
CPU-Target: 32Bit (64Bit)
Wohnort: Burgenland
Kontaktdaten:

Re: Wann Brauche ich Synchronize

Beitrag von af0815 »

Lomat hat geschrieben:
Di 14. Feb 2023, 13:32
https://github.com/serbod/dataport
Dort ist das Synchronize in der Komponente versteckt, genaugenommen in der Execute routine
if Assigned(FParentDataPort.OnDataAppear) then
Synchronize(SyncProc)
else
if Assigned(OnIncomingMsgEvent) then
OnIncomingMsgEvent(Self, sFromPort);
Deswegen brauchst du das nicht. Es wird intern gelöst.
Blöd kann man ruhig sein, nur zu Helfen muss man sich wissen (oder nachsehen in LazInfos/LazSnippets).

Lomat
Beiträge: 28
Registriert: Fr 14. Jan 2022, 13:44

Re: Wann Brauche ich Synchronize

Beitrag von Lomat »

Hallo und Danke nochmal,

ich habe die unnötigen Threads zum Laden und Speichern entfernt. Application.ProcessMessages half dabei, dass der Benuter den Vorgang auch ohne Multithreading abbrechen konnte. Die Ansteuerung der seriellen Schnittstelle klappt auch so weit. Hier war ein zusätzlicher Thread die besser Wahl. Etwas unschön ist, dass ich für meinen bisherigen Programmcode ein Fenster brauche. Dieses wird im Tread im Execute-Bereich erzeugt und mit dem Destructor wieder entfernt. Es dient nur als Container für den Timer und den "DataPort". Auf Zugriffe auf die Oberfläche dieses unsichtbaren Fensers habe ich zur Laufzeit verzichtet. Ich schau mal ob ich mir das Fenster in Zukunft sparen kann. Die Ereignisbehandlungsroutinen von "DataPor"t müssten dann manuell eingehängt werden. Das habe ich bisher noch nicht gemacht. Bis jetzt läuft alles stabil und störungsfrei.

Viele Grüße

Christoph

Benutzeravatar
theo
Beiträge: 10467
Registriert: Mo 11. Sep 2006, 19:01

Re: Wann Brauche ich Synchronize

Beitrag von theo »

Lomat hat geschrieben:
Di 14. Feb 2023, 16:20
Bis jetzt läuft alles stabil und störungsfrei.
Ich weiss nicht genau was du machst und das muss ich auch nicht. Es kann auch sein, dass dein Fall problemlos ist.
ABER: Eines kann ich dir aus Erfahrung sagen: Wenn du bei Multi-Threading oder Unicode sagen musst: "Bis jetzt läuft alles stabil und störungsfrei." dann weisst du eben nicht, was du getan hast und dann ist es sehr wahrscheinlich, dass es irgendwann kracht. :wink:
Der Fehler ist dann oft schwer zu finden und auszubügeln.

Antworten