Zugriffe auf Datenstruktur synchronisieren

Für Fragen zur Programmiersprache auf welcher Lazarus aufbaut

Re: Zugriffe auf Datenstruktur synchronisieren

Beitragvon Warf » 31. Aug 2017, 05:42 Re: Zugriffe auf Datenstruktur synchronisieren

braunbär hat geschrieben:
Der assembler hat nichts zu sagen, critical sections sind per definition atomar, während boolean Felder auf Compiler und Architektur ankommen.
Mit der neuen Fpc version könnte das schon ganz anders aussehen. Bei nicht definiertem verhalten darf man niemals Annahmen über das Verhalten machen.

Zum einen würde mich ein Link dazu interessieren.
Zum anderen wäre das in diesem Fall auch egal, weil auf der einen Seite nur gelesen, und auf der anderen nur geschrieben wird.
Entweder das Schreiben passiert "rechtzeitig", dann wird der Click in der aktuellen Schleife verarbeitet, oder es kommt zu spät, dann eben in der nächsten Schleife. Passieren kann nichts. Nebenbei würde ich die Wahrscheinlichkeit, dass in einer zukünftigen FPC Version das atomare movb bzw. cmpb durch irgend etwas anderes ersetzt wird, auf eine glatte Null einschätzen.

Delphi produziert hier übrigens auch ganz atomaren Code. Zumindest Delphi 5 und das RAD Studio 10.1 Berlin. Turbo Pascal 3 ebenfalls. :D
Die Versionen dazwischen habe ich nicht gecheckt.

PS: critical sections machen übrigens ein Check und set in einer Aktion, also ein der Wert wird ausgelesen, ein neuer wert wird geschrieben, in einem Tick. Ohne diese atomare Eigenschaft kann zwischen dem get und dem set unterbrochen werden, und dann denken beide Threads die Variable wäre nicht gesetzt und führen gleichzeitig Code aus. Mit critical sections ist das per Definition unmöglich, unabhängig von compilerverhalten, Optimierung oder Architektur

Das ist schon klar, hat aber mit der Aufgabenstellung hier nichts zu tun.


Tut mir leid, ich hatte gestern wohl ein paar Bierchen zu viel, und habe irgendwie deinen ersten Post mit dem von wp zusammen gelesen, und dachte du wölltest das über islocked lösen, dass ist nämlich alles andere als atomar.

Deine Lösung funktioniert so, allerhöchstens könnte es dazu führen das mit der Aktion ein kompletter Zyklus länger gewartet werden muss, aber ansonsten ist sie gut
Warf
 
Beiträge: 616
Registriert: 23. Sep 2014, 16:46
Wohnort: Aachen
OS, Lazarus, FPC: Mac OSX 10.11 | Win 10 | FPC 3.0.0 | L trunk | 
CPU-Target: x86_64, i368, ARM
Nach oben

Beitragvon braunbär » 31. Aug 2017, 09:37 Re: Zugriffe auf Datenstruktur synchronisieren

Warf hat geschrieben:Tut mir leid, ich hatte gestern wohl ein paar Bierchen zu viel,

Überhaupt kein Problem, das soll mir angeblich auch schon passiert sein - nicht mit Bier, das ist überhaupt nicht meins, aber Wein oder Cocktails können manchmal verdammt schnell im Glas verdunsten. :)

Braunbär hat geschrieben:Zum einen würde mich ein Link dazu interessieren.

Ist ernst gemeint. Hast du da etwas für mich? Dass derartige Zuweisungen oder Abfragen auf boolean nicht atomar sein könnten, habe ich noch nicht gehört. Bei bitpacked booleans natürlich, und bei kombinierten Lese- und Schreibvorgängen natürlich auch (das betrifft aber jeden Datentyp).
braunbär
 
Beiträge: 164
Registriert: 8. Jun 2017, 17:21

Beitragvon braunbär » 31. Aug 2017, 09:54 Re: Zugriffe auf Datenstruktur synchronisieren

Erst Invisible setzen statt zu löschen, und erst im nächsten Durchlauf von Timer1Timer die unsichtbaren Kreise wirklich zu löschen, ist übrigens eine einfache Möglichkeit, die (ohnedies sehr unwahrscheinlichen) Exceptions in der MouseDown Routine zu vermeiden. Weil ein unsichtbares Element kann nicht mehr angeklickt werden, und wenn erst beim nächsten Durchlauf der Timer Routine die unsichtbaren Elemente wirklich gelöscht werden, dann kann dort gar nichts mehr passieren. Das wäre noch besser, als die Exception mittels Try-except zu übergehen.
braunbär
 
Beiträge: 164
Registriert: 8. Jun 2017, 17:21

Beitragvon Warf » 31. Aug 2017, 11:31 Re: Zugriffe auf Datenstruktur synchronisieren

braunbär hat geschrieben:
Warf hat geschrieben:Tut mir leid, ich hatte gestern wohl ein paar Bierchen zu viel,

Überhaupt kein Problem, das soll mir angeblich auch schon passiert sein - nicht mit Bier, das ist überhaupt nicht meins, aber Wein oder Cocktails können manchmal verdammt schnell im Glas verdunsten. :)

Braunbär hat geschrieben:Zum einen würde mich ein Link dazu interessieren.

Ist ernst gemeint. Hast du da etwas für mich? Dass derartige Zuweisungen oder Abfragen auf boolean nicht atomar sein könnten, habe ich noch nicht gehört. Bei bitpacked booleans natürlich, und bei kombinierten Lese- und Schreibvorgängen natürlich auch (das betrifft aber jeden Datentyp).


Zu dem Link, das hatte ich vor nicht allzulanger Zeit in der Uni gelernt (Modul Betriebssysteme) daher kann ich dir dazu keinen Link geben, da alles was ich hatte das Skript von Professor ist. Und da stand einfach nur drin, normalerweise verwenden selbstgebaute schaltmechanismen (wie das lock von wp) zunächst eine Abfrage, und dann ein schreiben
Code: Alles auswählen
if not locked then
  Locked := true


Also 2 Anweisungen. Für critical sections stellt das OS normalerweise semaphores bereit, welche entweder einen checkandset Kommando ausführen (auf CISC) oder auf Risc Prozessoren, die keine eigene instruction dafür kennen, wird dann während diesen 2 instructions einfach kurz interrupts deaktiviert.

Somit ist gewährleistet dass zwischen diesen beiden instructions nie unterbrochen wird.

Das sollte auch irgendwo in der Linux Man stehen, finde es auf die schnelle aber grade nicht

Zu der Check and set habe ich aber zumindest mal das gefunden:
https://en.m.wikipedia.org/wiki/Test-an ... prov=sfti1
Warf
 
Beiträge: 616
Registriert: 23. Sep 2014, 16:46
Wohnort: Aachen
OS, Lazarus, FPC: Mac OSX 10.11 | Win 10 | FPC 3.0.0 | L trunk | 
CPU-Target: x86_64, i368, ARM
Nach oben

Beitragvon braunbär » 31. Aug 2017, 12:10 Re: Zugriffe auf Datenstruktur synchronisieren

Ok, dann ist es mir klarer und bezieht sich nicht speziell auf boolean.
Du hast natürlich Recht, dass für das sichere wechselseitige Locking asynchroner Prozesse Semaphore in irgend einer Form unabdingbar sind.
braunbär
 
Beiträge: 164
Registriert: 8. Jun 2017, 17:21

Beitragvon Warf » 31. Aug 2017, 12:11 Re: Zugriffe auf Datenstruktur synchronisieren

braunbär hat geschrieben:Ok, dann ist es mir klarer und bezieht sich nicht speziell auf boolean.
Du hast natürlich Recht, dass für das sichere wechselseitige Locking asynchroner Prozesse Semaphore in irgend einer Form unabdingbar sind.


Jap, auch wenn es hier nicht nötig wäre, finde ich man sollte sich das arbeiten mit critical sections auch bei so einfachen Aufgaben angewöhnen, und solche locks nicht selbst implementieren
Warf
 
Beiträge: 616
Registriert: 23. Sep 2014, 16:46
Wohnort: Aachen
OS, Lazarus, FPC: Mac OSX 10.11 | Win 10 | FPC 3.0.0 | L trunk | 
CPU-Target: x86_64, i368, ARM
Nach oben

Beitragvon Mathias » 31. Aug 2017, 16:41 Re: Zugriffe auf Datenstruktur synchronisieren

Ich hätte noch eine Anregung für einen besseren Bild-Lauf.

Bei Ramdomize würde ich noch ein
Code: Alles auswählen
  DoubleBuffered := True;
  Randomize;     

einfügen, so flimmert das Bild weniger.

Auch würde ich den Timer auf 40ms setzen, dafür aber auch RtgX und RtgY dem entsprechend kleiner wählen.
Mit Lazarus sehe ich gün
Mit Java und C/C++ sehe ich rot
Mathias
 
Beiträge: 3249
Registriert: 2. Jan 2014, 17:21
Wohnort: Schweiz
OS, Lazarus, FPC: Linux (die neusten Trunc) | 
CPU-Target: 64Bit
Nach oben

Beitragvon mintpc » 31. Aug 2017, 20:53 Re: Zugriffe auf Datenstruktur synchronisieren

Vielen Dank für die Hilfen, besonders an Braunbär, die Tipps hab ich aufgenommen und umgesetzt.

Was mich noch interessieren würde, sind diese "critical sections", die Warf erwähnt. Wo kann ich mich denn da mal genauer schlau machen? Gibts da gute Literatur zu?
mintpc
 
Beiträge: 112
Registriert: 6. Sep 2010, 17:39
Wohnort: Mailand
OS, Lazarus, FPC: Win 7 (L 1.6 FPC 3.0.0) | 
CPU-Target: Win 7
Nach oben

Beitragvon Warf » 1. Sep 2017, 05:32 Re: Zugriffe auf Datenstruktur synchronisieren

mintpc hat geschrieben:Vielen Dank für die Hilfen, besonders an Braunbär, die Tipps hab ich aufgenommen und umgesetzt.

Was mich noch interessieren würde, sind diese "critical sections", die Warf erwähnt. Wo kann ich mich denn da mal genauer schlau machen? Gibts da gute Literatur zu?


http://wiki.freepascal.org/Multithreade ... l_sections
Warf
 
Beiträge: 616
Registriert: 23. Sep 2014, 16:46
Wohnort: Aachen
OS, Lazarus, FPC: Mac OSX 10.11 | Win 10 | FPC 3.0.0 | L trunk | 
CPU-Target: x86_64, i368, ARM
Nach oben

Beitragvon mse » 1. Sep 2017, 07:53 Re: Zugriffe auf Datenstruktur synchronisieren

braunbär hat geschrieben:
Warf hat geschrieben:Verwende kein Boolean Feld. Zugriffe auf booleanfelder sind nicht atomar.

Wie kommst du darauf?
boolean.PNG

Viel atomarer als ein movb oder ein cmpb (s.Anhang) geht nicht. Ob auf der untersten Hardwareebene ein paar zusätzliche Taktzyklen gebraucht werden, um ein einzelnes Byte zu schreiben (beim lesen nicht einmal das), ist für den Programmablauf egal. Da fährt kein Interrupt dazwischen.

Darauf kann man sich bei Mehrkernprozessoren nicht mehr verlassen. Nicht unterbrechbare Operationen gibt es in Free Pascal in der unit system:
Code: Alles auswählen
 
function InterLockedIncrement (var Target: longint) : longint; public name 'FPC_INTERLOCKEDINCREMENT';
function InterLockedDecrement (var Target: longint) : longint; public name 'FPC_INTERLOCKEDDECREMENT';
function InterLockedExchange (var Target: longint;Source : longint) : longint; public name 'FPC_INTERLOCKEDEXCHANGE';
function InterLockedExchangeAdd (var Target: longint;Source : longint) : longint; public name 'FPC_INTERLOCKEDEXCHANGEADD';
function InterlockedCompareExchange(var Target: longint; NewValue: longint; Comperand: longint): longint; public name 'FPC_INTERLOCKEDCOMPAREEXCHANGE';
{$ifdef cpu64}
function InterLockedIncrement64 (var Target: int64) : int64; public name 'FPC_INTERLOCKEDINCREMENT64';
function InterLockedDecrement64 (var Target: int64) : int64; public name 'FPC_INTERLOCKEDDECREMENT64';
function InterLockedExchange64 (var Target: int64;Source : int64) : int64; public name 'FPC_INTERLOCKEDEXCHANGE64';
function InterLockedExchangeAdd64 (var Target: int64;Source : int64) : int64; public name 'FPC_INTERLOCKEDEXCHANGEADD64';
function InterlockedCompareExchange64(var Target: int64; NewValue: int64; Comperand: int64): int64; public name 'FPC_INTERLOCKEDCOMPAREEXCHANGE64';
{$endif cpu64}
{ Pointer overloads }
{$ifdef cpu64}
function InterLockedIncrement (var Target: Pointer) : Pointer; external name 'FPC_INTERLOCKEDINCREMENT64';
function InterLockedDecrement (var Target: Pointer) : Pointer; external name 'FPC_INTERLOCKEDDECREMENT64';
function InterLockedExchange (var Target: Pointer;Source : Pointer) : Pointer; external name 'FPC_INTERLOCKEDEXCHANGE64';
function InterLockedExchangeAdd (var Target: Pointer;Source : Pointer) : Pointer; external name 'FPC_INTERLOCKEDEXCHANGEADD64';
function InterlockedCompareExchange(var Target: Pointer; NewValue: Pointer; Comperand: Pointer): Pointer; external name 'FPC_INTERLOCKEDCOMPAREEXCHANGE64';
{$else cpu64}
function InterLockedIncrement (var Target: Pointer) : Pointer; external name 'FPC_INTERLOCKEDINCREMENT';
function InterLockedDecrement (var Target: Pointer) : Pointer; external name 'FPC_INTERLOCKEDDECREMENT';
function InterLockedExchange (var Target: Pointer;Source : Pointer) : Pointer; external name 'FPC_INTERLOCKEDEXCHANGE';
function InterLockedExchangeAdd (var Target: Pointer;Source : Pointer) : Pointer; external name 'FPC_INTERLOCKEDEXCHANGEADD';
function InterlockedCompareExchange(var Target: Pointer; NewValue: Pointer; Comperand: Pointer): Pointer; external name 'FPC_INTERLOCKEDCOMPAREEXCHANGE';
{$endif cpu64}
{ unsigned overloads }
function InterLockedIncrement (var Target: cardinal) : cardinal; external name 'FPC_INTERLOCKEDINCREMENT';
function InterLockedDecrement (var Target: cardinal) : cardinal; external name 'FPC_INTERLOCKEDDECREMENT';
function InterLockedExchange (var Target: cardinal;Source : cardinal) : cardinal; external name 'FPC_INTERLOCKEDEXCHANGE';
function InterLockedExchangeAdd (var Target: cardinal;Source : cardinal) : cardinal; external name 'FPC_INTERLOCKEDEXCHANGEADD';
function InterlockedCompareExchange(var Target: cardinal; NewValue: cardinal; Comperand: cardinal): cardinal; external name 'FPC_INTERLOCKEDCOMPAREEXCHANGE';
{$ifdef cpu64}
function InterLockedIncrement64 (var Target: qword) : qword; external name 'FPC_INTERLOCKEDINCREMENT64';
function InterLockedDecrement64 (var Target: qword) : qword; external name 'FPC_INTERLOCKEDDECREMENT64';
function InterLockedExchange64 (var Target: qword;Source : qword) : qword; external name 'FPC_INTERLOCKEDEXCHANGE64';
function InterLockedExchangeAdd64 (var Target: qword;Source : qword) : qword; external name 'FPC_INTERLOCKEDEXCHANGEADD64';
function InterlockedCompareExchange64(var Target: qword; NewValue: qword; Comperand: qword): int64; external name 'FPC_INTERLOCKEDCOMPAREEXCHANGE64';
{$endif cpu64}
 

Da im Beispiel AFAIK keine threads und mehrere Prozesse vorkommen, ist das Problem eher in der Listenverwaltung zu suchen wie braunbär schreibt.
mse
 
Beiträge: 1705
Registriert: 16. Okt 2008, 09:22
OS, Lazarus, FPC: Linux,Windows,FreeBSD,(MSEide+MSEgui 4.4.2,git master FPC 3.0,fixes_3_0) | 
CPU-Target: x86,x64,ARM
Nach oben

• Themenende •
Vorherige

Zurück zu Freepascal



Wer ist online?

Mitglieder in diesem Forum: 0 Mitglieder und 5 Gäste

porpoises-institution
accuracy-worried