nur mal btw... die Critical Section (CS) muss für alle (beteiligten) Threads sichtbar sein...
das CS-Exemplar wird bei der zu schützenden Resource gebildet und nicht innerhalb der Threads...
CS sind dafür geeigent, bestimmte Dinge gezielter zu synchronisieren... z.B. 2 unterschiedliche Resourcen, die von mehreren Threads gelesen/beschrieben werden... Wenn jede Resource eine eigene CriticalSection besitzt, wird mit der jeweiligen CS der Schreib/Lesezugriff auf diese eine Resource serialisiert...
ohne dabei Threads zu behindern, welche andere Resourcen und Critical Sections maltretieren...
Dabei versucht dann jeder Thread die Resource für sich zu reservieren...Im Falle, dass sie bereits reserviert ist, muss er warten (
TryEnterCriticalSection wäre das nicht-blockierende Pendant, aber nur NT und auch nicht in der Klasse TCriticalSection enthalten.)
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24: 25: 26: 27: 28: 29: 30: 31: 32: 33:
| _______________ | | | Thread A | __________ | CS1.Enter----------------. | | ____________ |_______________| | | CS 1 | | | _______________ '----------------------------> Daten I | | | ,------------>X | |____________| | Thread B | | |__________| | CS1.Enter----------------' |_______________| _______________ | | | Thread C | __________ | CS2.Enter----------------. | | _____________ |_______________| | | CS 2 | | | _______________ '----------------------------> Daten II | | | ,------------>X | |_____________| | Thread D | | ,---------->X | | CS2.Enter----------------' | |__________| |_______________| | _______________ | | | | | Thread E | | | CS2.Enter------------------' |_______________|
---> Reservierungsanfrage -->X Anfrage wird gehalten, bis Resource wieder freigegeben wird (CS.Enter blockiert) |
der Nachteil bei Critical Sections ist, dass sie auch Lesezugriffe serialisieren: d.h. wenn kein Thread schreibt, dafür alle lesen, dann kommt sich eigentlich keiner ins Gehege... also bedarf es dann
auch keiner Synchronisierung...
Bei der CS müssen aber dennoch alle Lesezugriffe konsequent synchronisiert werden, da man nicht lesen darf, wenn gerade wer schreiben KÖNNTE. Das Problem dabei ist eben, dass bei der reinen CS keine Fallunterscheidung stattfindet... ob nun wer schreibt oder nicht und somit der Fluss immer wieder aufgehalten wird...
das macht das Ganze also oftmals unperformant...
Um mehrere "parallele" Lesezugriffe zu ermöglichen und Schreibzugriffe zu serialisieren, hat Borland den TMultiReadExclusiveWriteSynchronizer (MREW) implementiert, welcher intern ebenfalls eine CS nutzt + Fallunterscheidung.
(Der MREW soll allerdings Deadlock-Effekte aufweisen, laut Borland QC und NG. Ich weiß garnicht mehr, wie die offzielle Stellungsnahme von Borland dazu war... Entweder man sucht eine Alternative, schustert sich selbst was zusammen oder man verwendet weiterhin MREW und hofft... (die VCL nutzt selbst teilweise MREW...))
wie motzi bereits erwähnte: wichtig ist das Leave (CS), EndWrite/Read (MREW) im Finally-Block... zur Not kann man auch dort mit der Funktion
ExceptObject auf Exceptions reagieren... (on = is usw.) alternativ kann man auch den Referenzzähler von Schnittstellen misbrauchen... bei Funktionsaustritt und damit verlorener Referenz: Unlock... is aber nich unbedingt schön und birgt Fehlerquellen... (aber netter Effekt für Restore-Objekte anderer Art...)