Wann Brauche ich Synchronize
Wann Brauche ich Synchronize
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
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
-
- Beiträge: 2118
- Registriert: Di 23. Sep 2014, 17:46
- OS, Lazarus, FPC: Win10 | Linux
- CPU-Target: x86_64
Re: Wann Brauche ich Synchronize
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
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
Re: Wann Brauche ich Synchronize
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
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
- af0815
- Lazarusforum e. V.
- Beiträge: 6771
- 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
Genau dann, wenn es so ist, wie du schreibst brauchst du keinen Thread, weil gegenseitig gestoppt wird.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?
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).
-
- Beiträge: 2118
- Registriert: Di 23. Sep 2014, 17:46
- OS, Lazarus, FPC: Win10 | Linux
- CPU-Target: x86_64
Re: Wann Brauche ich Synchronize
Deine Beschreibung oben klingt für mich als wäre application.processmessages vermutlich ausreichend um die ausstehenden events abzuarbeiten.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?
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
Re: Wann Brauche ich Synchronize
Wieso hast du das überhaupt gemacht?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.
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.
Re: Wann Brauche ich Synchronize
Dafür gibt es TCsvDocument: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.
https://wiki.freepascal.org/CsvDocument
https://www.freepascal.org/daily/doc/fc ... ument.html
Re: Wann Brauche ich Synchronize
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
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
Re: Wann Brauche ich Synchronize
Soweit ich das verstehe, hat man den Haupthread drin, sobald man eine TForm ein TBitmap etc. benutzt. Jedenfalls auf Linux.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.
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.

https://wiki.lazarus.freepascal.org/Mul ... n_Tutorial
- af0815
- Lazarusforum e. V.
- Beiträge: 6771
- 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
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.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.
Blöd kann man ruhig sein, nur zu Helfen muss man sich wissen (oder nachsehen in LazInfos/LazSnippets).
Re: Wann Brauche ich Synchronize
Hallo, es ist die DataPort-Komponenten von Sergey Bodrov.
- af0815
- Lazarusforum e. V.
- Beiträge: 6771
- 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
Dort ist das Synchronize in der Komponente versteckt, genaugenommen in der Execute routine
Deswegen brauchst du das nicht. Es wird intern gelöst.if Assigned(FParentDataPort.OnDataAppear) then
Synchronize(SyncProc)
else
if Assigned(OnIncomingMsgEvent) then
OnIncomingMsgEvent(Self, sFromPort);
Blöd kann man ruhig sein, nur zu Helfen muss man sich wissen (oder nachsehen in LazInfos/LazSnippets).
Re: Wann Brauche ich Synchronize
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
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
Re: Wann Brauche ich Synchronize
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.

Der Fehler ist dann oft schwer zu finden und auszubügeln.