Multitasking die 1.: CriticalSection

Für Fragen von Einsteigern und Programmieranfängern...
Warf
Beiträge: 2118
Registriert: Di 23. Sep 2014, 17:46
OS, Lazarus, FPC: Win10 | Linux
CPU-Target: x86_64

Re: Multitasking die 1.: CriticalSection

Beitrag von Warf »

mschnell hat geschrieben:Scheint wohl ein generell schwieriges Problem zu sein. In C# und vielen anderen Sprachen sind Strings "reaonly": wenn man einen String verändern will, muss man immer einen neuen machen.
-Michael
Das mit C# hat aber andere Gründe, genauso wie bei Java ist in C# der Heap ein stack. Resizing ist eh also nicht möglich und direkten Speicherzugriff erlaubt C# (und java) auch nicht.

In C++ geht das ganz einfach, da kann man einen Char array in einen shared (oder unique) pointer reinsetzen, die machen intern referenzzählung, und garantieren das die threadsicher ist.

Alles was dier FPC machen müsste damit das auch da funktioniert ist, zu jedem string neben ReferenzCount, Länge und Daten noch eine CriticalSection hinzuzufügen (ein String ist intern ja nur ein record, also muss da nur ein feld mehr in den record), und bei jeder operation auf strings die in ein try-finally setzen in der der string gelockt wird bevor was gemacht wird.

Könnte man ja auch einen neuen typen für einführen (ThreadsafeString oder so) oder das man das über compilerswitch ein/aus stellen kann

Socke
Lazarusforum e. V.
Beiträge: 3177
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: Multitasking die 1.: CriticalSection

Beitrag von Socke »

Warf hat geschrieben:Alles was dier FPC machen müsste damit das auch da funktioniert ist, zu jedem string neben ReferenzCount, Länge und Daten noch eine CriticalSection hinzuzufügen (ein String ist intern ja nur ein record, also muss da nur ein feld mehr in den record), und bei jeder operation auf strings die in ein try-finally setzen in der der string gelockt wird bevor was gemacht wird.
Das funktioniert nicht. Das Problematische ist nicht die Referenzzählung sondern, dass Dereferenzierung und Referenzzählung zusammen nicht atomar sind. Insofern wird Dereferenzierung und Critical Section auch nicht atomar.
MfG Socke
Ein Gedicht braucht keinen Reim//Ich pack’ hier trotzdem einen rein

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

Re: Multitasking die 1.: CriticalSection

Beitrag von Warf »

Socke hat geschrieben:Das funktioniert nicht. Das Problematische ist nicht die Referenzzählung sondern, dass Dereferenzierung und Referenzzählung zusammen nicht atomar sind. Insofern wird Dereferenzierung und Critical Section auch nicht atomar.
Hä? der Referenzzähler wird doch nur angepackt beim Assignment, nicht bei der Dereferenzierung. Das heißt die einzige möglichkeit ein Use-After Free zu haben ist wenn der Referenzzähler dekrementiert wird bevor er inkrementiert wird. Alle anderen zugriffe sind sicher (naja zumindest im hinblick auf speicherzugriffe, nicht im hinblick auf datenkonsistenz, darum geht es aber nicht).
Wenn ich schreibe:

Code: Alles auswählen

s1 := s2;
macht der FPC daraus ungefähr:

Code: Alles auswählen

Dec(s1^.RefCount);
if s1^.RefCount = 0 then Dispose(s1);
s1 := s2;
Inc(s2^.RefCount);
Der fehler kommt daher das diese gesammte operation atomar sein muss. Aber was hält den FPC davon ab die beiden Referenzoperationen in eine CS zu packen?

Es geht hier nicht um den zugriff, auch wenn beim zugriff auf den String die daten inkonsistent sein können, ist das egal. Es geht einzig und allein um den Use-After-Free fehler den man bei meinem Beispiel oben bekommt. Das ist ein reiner Fehler durch inkonsistente Referenzzählung.

Ich mein in C++ funktioniert es ja, also warum sollte es mit Pascal nicht gehen?

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: Multitasking die 1.: CriticalSection

Beitrag von mschnell »

Warf hat geschrieben: Alles was der FPC machen müsste damit das auch da funktioniert ist, zu jedem string neben ReferenzCount, Länge und Daten noch eine CriticalSection hinzuzufügen
Das würde aber schwer auf die Performance gehen. Wenn fpc für Critical Section in Linux die pthreadLib verwendet (weiß ich aber nicht) ist das ein aufwendiger function call, würde aber immerhin - falls die Architektur das unterstützt - einen Futex (->https://linux.die.net/man/7/futex) verwenden. Wenn fpc direkt die Mutex API verwendet wird es noch viel langsamer (Wechsel in den Kernel space). Eine eigene FUTEX-Implementierung - die wenig Overhead erzeugen würde - hat fpc soweit ich weiß nicht.
In Windows geht vermutlich nur der Call in die entsprechende DLL, der macht aber sowas ähnliches wie FUTEX - aber bestimmt weniger effizient als Linux.
-Michael

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

Re: Multitasking die 1.: CriticalSection

Beitrag von Warf »

mschnell hat geschrieben:Das würde aber schwer auf die Performance gehen. Wenn fpc für Critical Section in Linux die pthreadLib verwendet (weiß ich aber nicht) ist das ein aufwendiger function call, würde aber immerhin - falls die Architektur das unterstützt - einen Futex (->https://linux.die.net/man/7/futex) verwenden.
Wenn man die cthreads unit verwendet müssten pthreads verwendet werden. Aber klar geht das auf die performance. Unter C wird ja statisch gegen pthread lib gelinkt, und wenn man dann LTO (Link Time Optimization) aktiviert, können die Calls geinlined werden was kaum performanceverlust hat. In wie fern Optimierungen beim FPC funktionieren, keine ahnung. Natürlich hat locking immer performanceauswirkungen (selbst wenns super effizient ist), weshalb das wenn ja nicht allgemein gelten sollte (die meisten anwendungen sind ja nicht unbedingt gethreaded, oder wenn mit sehr schmalen schnittstellen) sondern ein eigener typ den man dann benutzen kann wenn es benötigt wird

Antworten