多线程文件通过现有对象写入

Jee*_*dee 2 delphi multithreading

应用说明:

我有一个应用程序,允许用户通过线程运行多个并发查询(一次最多100个).

我有一个用于记录错误的类.如果应用程序中发生错误,我创建该类的实例并调用过程将错误写入日志文件.

题:

我需要使错误记录代码线程安全.我注意到如果很多线程同时运行并产生相同的错误(例如无法连接到数据库),我会收到i/o错误32(由于应用程序试图写入一个文件而导致已经开放).

作为一个快速而肮脏的修复,我将写入文件的代码放入try ...除了重复循环内的块之外.如果存在异常(例如,该文件已被该类的另一个实例打开,由另一个线程启动),则它将标志设置为"false".循环继续执行,直到标志为"true"(即没有错误写入文件),如下所示:

procedure TErrorLogging.logError(error: string);
var
     f: textfile;
     ok: boolean;
begin
     repeat
          ok := true;
          try
               assignfile(f, fLogFilename);
               if fileExists(fLogFilename) then append(f) else rewrite(f);
               writeln(f, error);
               closefile(f);
          except
               ok := false;
          end;
     until ok;
end;
Run Code Online (Sandbox Code Playgroud)

我知道保护代码块的正确方法是使用Critical Sections,但我不确定如何实现它,因为有许多不同的线程使用了日志记录类,并且每个实例该线程有自己的日志记录类实例,它用于写入文件(因此它们不仅仅是针对同一代码块进行同步).

选项,我可以看到它们:

  1. 使用上面的代码.保留此代码是否有任何问题?这是一个快速而肮脏的修复,但它的工作原理.
  2. 使用全局TCriticalSection(如何?).
  3. 在某个地方使用单个过程创建一个日志记录类的实例,线程将对其进行同步(我认为这会破坏拥有日志记录类的对象).

TLa*_*ama 6

每当要添加日志条目时创建日志记录类的实例都是错误的,并且反复打开和关闭日志文件.我个人会使用一个类的一个实例,它在内部使用一个字符串列表,其基本方法是线程安全的.像这样的东西:

type
  TErrorLog = class
  private
    FList: TStringList;
    FLock: TRTLCriticalSection;
  public
    constructor Create;
    destructor Destroy; override;
    procedure Clear;
    procedure Add(const ErrorText: string);
    procedure SaveToFile(const FileName: string);
  end;

implementation

{ TErrorLog }

constructor TErrorLog.Create;
begin
  inherited Create;
  InitializeCriticalSection(FLock);
  FList := TStringList.Create;
end;

destructor TErrorLog.Destroy;
begin
  EnterCriticalSection(FLock);
  try
    FList.Free;
    inherited Destroy;
  finally
    LeaveCriticalSection(FLock);
    DeleteCriticalSection(FLock);
  end;
end;

procedure TErrorLog.Clear;
begin
  EnterCriticalSection(FLock);
  try
    FList.Clear;
  finally
    LeaveCriticalSection(FLock);
  end;
end;

procedure TErrorLog.Add(const ErrorText: string);
begin
  EnterCriticalSection(FLock);
  try
    FList.Add(ErrorText);
  finally
    LeaveCriticalSection(FLock);
  end;
end;

procedure TErrorLog.SaveToFile(const FileName: string);
begin
  EnterCriticalSection(FLock);
  try
    FList.SaveToFile(FileName);
  finally
    LeaveCriticalSection(FLock);
  end;
end;
Run Code Online (Sandbox Code Playgroud)