TCriticalSection ist ja Windows
EnterCriticalSection, auch wenn Delphi diese Klasse schon für andere Plattformen erweitert hat.
Hier könnte man zwar auch einen MultiReaderSingleWriter verwenden, da sich das Dictionary parallel auslesen ließe, aber wenn nicht soooooo oft gelesen wird, dann lohnt es sich nicht.
TSimpleRWSync bzw.
TMultiReadExclusiveWriteSynchronizer/TMREWSync
Dann gibt es noch das "neuere" TMonitor in der System-
Unit, welches sich nativ an jedes TObject hängen lässt. (mit dem Namen der nicht mit TMonitor aus Forms zu verwechseln ist)
Es gibt auch eine TThreadList, was eine TList ist und bereits sowas wie eine CriticalSection enthält.
Add, Remove und Clear sind bereits threadsave und ansonsten kann man sich die innere TList auch gesperrt rausholen und längere Aktionen mit der Liste machen, während die anderen Threads warten.
Und im Grunde kommt kommt alles auf's Gleiche drauf raus, du mußt die Liste sperren (mindestens) wenn die Liste bearbeitet wird, bzw. auch für die "kurze" Rechenpause zwischen Nachsehn und das Machen.
Delphi-Quellcode:
TMonitor.Enter(List);
try
if not List.Find(xyz) then
List.Add(xyz);
finally
TMonitor.Exit(List);
end;
Atomare Operationen braucht man nicht selbst absichern, wie z.B. InterlockedIncrement bzw. das plattformunabhängige AtomicIncrement oder das TThreadList.Add,
aber alles Andere muß geschützt werden, wie z.B. im Beispeispiel die Lücke zwischen If, Find und Add, wo ja ein anderer Thread zwischendurch das auch einfügen kann und das Ergebnis vom IF somit schon nicht mehr stimmt, wenn Add ausgeführt wird.
Alle anderen Sperr-Klassen mußt du ja neben dein zu Sperrendes legen, während TMonior direkt an der Klasse hängt, aber mit dem "Nachteil", dass man in der Definition nichts von dieser Sperr-Instanz sieht.
Hier kann man aber das Verhalten des Compilers ausnutzen, dass er unbekannte Attributklassen einfach ignoriert,
um hier in der Deklaration zu "dokumentieren", dass unten TMonitor verwendet wird.
Delphi-Quellcode:
var
[Monitor] // oder [Lock]
List: TDictionary<string,string>;
Delphi-Quellcode:
type
MonitorAttribute = class(TAttribute);
var
[Monitor]
List: TDictionary<string,string>;
PS: Globale Variablen sind eh böse und ich würde das Dictionary als Class Var in die Threadklasse integrieren.
Delphi-Quellcode:
type
TMyThread = class(TThread)
public class var
List: TDictonary<string,string>;
protected
procedure Execute; override;
end;
// von außerhalb
TMyThread.List[abx] := def; //TMyThread.List.Add(abx, def);