Does Delphi read by TList <x> thread safe?

I created a simple logging class and want to confirm that it is thread safe. Basically Log , RegisterLogger and UnRegisterLogger will be called from different threads. Log will be called a lot (from many different threads) and RegisterLogger and UnRegisterLogger infrequently.

Basically, my question can be summarized as follows: β€œIs reading TList<x> thread safe?”, That is, can I have multiple threads accessing TList at the same time.

IExecutionCounterLogger is an interface with the Log method (with the same signature as TExecutionCounterServer.Log )

 Type TExecutionCounterServer = class private Loggers : TList<IExecutionCounterLogger>; Synchronizer : TMultiReadExclusiveWriteSynchronizer; public procedure RegisterLogger(Logger : IExecutionCounterLogger); procedure UnRegisterLogger(Logger : IExecutionCounterLogger); procedure Log(const ClassName, MethodName : string; ExecutionTime_ms : integer); constructor Create; destructor Destroy; override; end; constructor TExecutionCounterServer.Create; begin Loggers := TList<IExecutionCounterLogger>.Create; Synchronizer := TMultiReadExclusiveWriteSynchronizer.Create; end; destructor TExecutionCounterServer.Destroy; begin Loggers.Free; Synchronizer.Free; inherited; end; procedure TExecutionCounterServer.Log(const ClassName, MethodName: string; ExecutionTime_ms: integer); var Logger: IExecutionCounterLogger; begin Synchronizer.BeginRead; try for Logger in Loggers do Logger.Log(ClassName, MethodName, ExecutionTime_ms); finally Synchronizer.EndRead; end; end; procedure TExecutionCounterServer.RegisterLogger(Logger: IExecutionCounterLogger); begin Synchronizer.BeginWrite; try Loggers.Add(Logger); finally Synchronizer.EndWrite; end; end; procedure TExecutionCounterServer.UnRegisterLogger(Logger: IExecutionCounterLogger); var i : integer; begin Synchronizer.BeginWrite; try i := Loggers.IndexOf(Logger); if i = -1 then raise Exception.Create('Logger not present'); Loggers.Delete(i); finally Synchronizer.EndWrite; end; end; 

Like a little more background, this is the next of this question . Basically, I added some tools for each method (DCOM) of the DataSnap server, I also connected to each OnDataData and OnUpdateData event in TDataSnapProvider.

+6
source share
2 answers

Reads TList<T> thread safety? That is, can I have multiple threads accessing TList<T> at the same time?

It is thread safe and does not require synchronization. Multiple threads can safely read at the same time. This is equivalent to (and actually implemented as) reading from an array. Only if one of your threads modifies the list that is required for synchronization.

Your code is a little more complicated than this script. It seems you need to serve the streams that modify the list. But you did it with TMultiReadExclusiveWriteSynchronizer , which is the perfect solution. It allows multiple read streams to work simultaneously, but any write streams are serialized with respect to all other streams.

+8
source

By highlighting the first part of your question, you state that the RegisterLogger and UnregisterLogger calls are infrequent. While the log call only reads the list, the other two change the list. In this case, you must ensure that none of them are executed at run time or that a log call may occur.

Imagine that Delete in UnregisterLogger is executed during a for loop in the log. The results are at least unpredictable.

It is not enough to use the Synchronizer only in these two write calls.

So the answer to your question

Is reading in a TList stream safe?

it can only be: it depends!

If you can make sure that RegisterLogger and UnregisterLogger are not registered (i.e. only read requests can be executed), you can safely lower the synchronizer. Otherwise, it’s better not.

+2
source

All Articles