我已经构建了一个简单的日志记录类,并希望确认它是线程安全的.基本上,将从不同的线程调用Log,RegisterLogger和UnRegisterLogger.日志将很少被调用(来自许多不同的线程)和RegisterLogger和UnRegisterLogger很少.
基本上我的问题可归结为:“读取TList< x>线程是否安全?”,也就是说我可以让多个线程同时访问TList.
IExecutionCounterLogger是一个带有Log方法的接口(与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;
作为更多背景,这是从this question开始的.我基本上已经为(DCOM)DataSnap服务器的每个方法添加了一些工具,我也已经连接到每个TDataSnapProvider OnGetData和OnUpdateData事件.
解决方法
Are reads on
TList<T>
thread safe? That is to say can I have multiple threads accessing aTList<T>
at the same time?
这是线程安全的,不需要同步.多个线程可以安全地同时读取.这相当于(并且实际上实现为)从数组中读取.只有当您的某个线程修改了需要同步的列表时.
您的代码比此方案稍微复杂一些.您似乎需要满足修改列表的线程.但是你已经使用TMultiReadExclusiveWriteSynchronizer这样做了,这是一个非常好的解决方案.它允许多个读取线程同时操作,但任何写入线程都相对于所有其他线程进行序列化.