Delphi-PRAXiS
Seite 3 von 4     123 4      

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Algorithmen, Datenstrukturen und Klassendesign (https://www.delphipraxis.net/78-algorithmen-datenstrukturen-und-klassendesign/)
-   -   Critical Section um globale Methode? (https://www.delphipraxis.net/192619-critical-section-um-globale-methode.html)

himitsu 7. Jun 2017 15:16

AW: Critical Section um globale Methode?
 
Zitat:

Zitat von SneakyBagels (Beitrag 1373722)
Das verstehe ich jetzt nicht. Wofür denn nun Monitor und eine CS?

Im Prinzip ist Beides das Gleiche, nur mit 'ner anderen Syntax.

Ist wie der unterschied zwischen
Delphi-Quellcode:
StringList[123]
und
Delphi-Quellcode:
StringList.Strings[123]
.



Abgesehn, dass TMonitor was "Eigenes" ist und TCriticalSection die API vom Windows kapselt, aber von der Funktion her sind die schon vergleichbar.

SneakyBagels 7. Jun 2017 15:19

AW: Critical Section um globale Methode?
 
Ok dann bleibe ich wohl bei CriticalSections.
Die sind mir vom Aufbau her so oder so logischer.
Ich selber konnte bei meinen Tests keinerlei Performanceunterschied feststellen.
Scheinen wohl nur Nanosekunden zu sein.

himitsu 7. Jun 2017 15:23

AW: Critical Section um globale Methode?
 
In Delphi gibt es noch viel mehr Implementationen, die das Gleiche wie eine CriticalSection/TMonitor erledigen.

Dann noch paar Dinger mit Zusatzfunktionen, wie z.B. den TMultiReadExclusiveWriteSynchronizer (TMREWSync), welcher parallele Lesezugriffe erlaubt und nur bei einem Schreibzugriff alles komplett sperrt.
Und für Zugriffe auf einzelne Interger, Pointer, Booleans und anderen Kleinkram gibt es mehrere Interlocked-Implementationen, welche atomare Schreibzugriffe ermöglichen.

SneakyBagels 7. Jun 2017 15:37

AW: Critical Section um globale Methode?
 
Zitat:

Dann noch paar Dinger mit Zusatzfunktionen, wie z.B. den TMultiReadExclusiveWriteSynchronizer (TMREWSync), welcher parallele Lesezugriffe erlaubt und nur bei einem Schreibzugriff alles komplett sperrt.
Das ist interessant zu wissen! Ich dachte immer nur, hier würde nur für lesenden Zugriff gesperrt.
Aber heißt das jetzt, dass sobald ich bei Verwendung von TMultiReadExclusiveWriteSynchronizer irgendwo trotzdem schreibe, nur dieser eine schreibende Zugriff geblockt wird?
Wenn ja dann wäre das ja ein recht großer Vorteil denn statt 100 von 100 "Dingern" zu blocken (wo ich 1x schreibe und 99x lese) würde hier nur 1x geblockt. Sehe ich das richtig?

Dass ich schreibenden Zugriff hier mit BeginWrite und EndWrite absichern muss ist klar. Aber wofür den lesenden?

Edit:
durch die Verwendung eines globalen TMultiReadExclusiveWriteSynchronizer und BeginWrite/EndWrite, welches ich NUR dort verwende wo ich meiner Klasseninstanz Daten zuweise, ist meine Prozedur rund 5% schneller geworden. Kann das daran liegen, dass ich nun nicht mehr rigoros alles blockiere sondern nur noch den schreibenden Zugriff?

Zacherl 7. Jun 2017 16:01

AW: Critical Section um globale Methode?
 
Zitat:

Zitat von SneakyBagels (Beitrag 1373744)
durch die Verwendung eines globalen TMultiReadExclusiveWriteSynchronizer und BeginWrite/EndWrite, welches ich NUR dort verwende wo ich meiner Klasseninstanz Daten zuweise, ist meine Prozedur rund 5% schneller geworden. Kann das daran liegen, dass ich nun nicht mehr rigoros alles blockiere sondern nur noch den schreibenden Zugriff?

Korrekt. Der
Delphi-Quellcode:
TMultiReadExclusiveWriteSynchronizer
ist für solche Szenarien besser geeignet, als
Delphi-Quellcode:
TCriticalSection
oder
Delphi-Quellcode:
TMonitor
. Solange jetzt n-Threads gleichzeitig NUR lesen, wirst du einen Performancevorteil feststellen können. Im Grunde stellt der
Delphi-Quellcode:
TMultiReadExclusiveWriteSynchronizer
jetzt nur noch sicher, dass erst alle lesenden Zugriffe abgeschlossen sind, bevor ein schreibender Zugriff stattfindet und blockiert während dieser Zeit dann alle lesenden Operationen (deshalb musst du trotzdem signalisieren, an welchen Stellen du lesen willst).

Mit
Delphi-Quellcode:
TCriticalSection
oder
Delphi-Quellcode:
TMonitor
hingegen, kann auch nur ein einziger Thread gleichzeitig lesen.

himitsu 7. Jun 2017 16:12

AW: Critical Section um globale Methode?
 
Lesezugriffe sperren sich nicht gegenseitig ... mehrere sind erlaubt.
So lange es Lesesperren gibt, warten alle Schreibanfragen.
Eine Schreibsperre sperrte alle anderen Lese und Schreibzugriffe.

Natürlich nur verwendbar für "echte" Lesezugriffe, wo wirklich nichts geschrieben wird.
z.B. Stream.Read ist zwar ein Lesezugriff, aber da bei wird der Positionszeiger geändert, was einen Schreibzugriff darstellt.

Aber sonst können mehrere ungehindert gleichzeitig lesen
und wenn Einer was schreiben will, dann ist so lange alles gesperrt.
MultiReader ist demnach besonders hilfreich, bei vielen Lesezugriffen und seltenen Schreibzugriffen.

Bei der CriticalSection und dem TMonitor ist immer alles gesperrt, egal ob lesen oder schreiben.
(nur Zugriffe aus dem selben Thread sind erlaubt, da sie per se threadsave sind und man so keinen Deadlock riskiert, wenn man in einem Thread verschachtelt Enter aufruft)

SneakyBagels 7. Jun 2017 16:58

AW: Critical Section um globale Methode?
 
Mhhh ok das heißt also

Delphi-Quellcode:
-thread-instanzen 1+2+3 (alle selber Code, nur unterschiedliche Listen sind abzuarbeiten)
begin
 schleife anfang

 _globals.aMultiReadExclusiveWriteSynchronizer.BeginWrite;
 setze globale Klasseninstanz := Liste.Items[i]
 _globals.aMultiReadExclusiveWriteSynchronizer.EndWrite;

 (a)
 ...
 lese hier
 ...
 lese dort
 ...
 lese nochmals hier
 (b)

 schleife ende
end;
So habe ich das aktuell. Jeder Thread kann der globale Klasseninstanz ein Item zuweisen. An anderen Stellen (nicht in diesem Thread) lese ich die Klasseninstanz dann aus und zeige die dahinterliegenden Daten auf der Benutzeorberfläche an.

Ist das so richtig oder müsste ich jetzt noch zusätzlich von (a) bis (b) ein _globals.aMultiReadExclusiveWriteSynchronizer.Begi nRead; und EndRead setzen?

himitsu 7. Jun 2017 17:35

AW: Critical Section um globale Methode?
 
Dort, wo lesend auf globale-Klasseninstanz zugegriffen wird, kommt natürlich ein BeginRead drumrum.

Erstmal reicht es den Lese-Zugriff auf diese Variable zu sperren,
aber wenn sich innerhalb dieser Instanz auch etwas ändern kann (Property und enthaltene Variablen), dann auch das mit einschließen.

Wenn sich an der Objektinstanz nicht gleichzeig in mehreren Thread was ändert,
also z.B. da was einstellen, dann die Variable setzen und jemand Anderes liest dann nur diese Variable, oder holt sich sie da raus (auslesen und NIL setzen),
dann kann man auch mit InterlockedExcange oder den neuen TLock-irgendwas-Klassen in der System-Unit arbeiten.

SneakyBagels 7. Jun 2017 17:39

AW: Critical Section um globale Methode?
 
Da achte ich strikt drauf. Erst ändere ich und dann lese ich. Danach wird erstmal nicht mehr geändert. Im jedem Schleifendurchgang gibt es nur eine einzige Änderung.
Wofür ist es denn wichtig den lesenden Zugriff zu sperren?
Wenn man 5 Thread-Instanzen hat, alle haben die gleichen Dinge abzuarbeiten, man aber den lesen Zugriff blockieren muss, kann man dann hier überhaupt noch von Multithreading reden?

Erste Tests zeigen, dass wenn ich überall den lesenden Zugriff blockiere der Code doppelt so lange braucht als vorher.
Den lesenden Zugriff hatte ich früher noch nie blockiert, immer nur den schreibenden.

himitsu 7. Jun 2017 17:53

AW: Critical Section um globale Methode?
 
Die Lesedinge sperren sich dabei nicht gegenseitig.

Das BeginRead ist nur dafür da, um zu verhindern, dass jemand während des Lesens etwas ändern kann.
BeginRead sperrt das BeginWrite, bzw. hält selber an, wenn gerade geschrieben wird.
Andere BeginRead werden aber durch den Read-Lock (durch BeginRead) nicht beeinflusst.


Alle Zeitangaben in WEZ +1. Es ist jetzt 02:59 Uhr.
Seite 3 von 4     123 4      

Powered by vBulletin® Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz