6

単純なロギング クラスを作成しましたが、それがスレッド セーフであることを確認したいと考えています。基本的にLogRegisterLoggerUnRegisterLoggerは異なるスレッドから呼び出されます。 Log(多くの異なるスレッドから)頻繁RegisterLoggerに呼び出されます。UnRegisterLogger

基本的に私の質問は、「スレッドでの読み取りはTList<x>安全ですか?」ということです。つまり、複数のスレッドTListが同時にアクセスすることはできますか?

IExecutionCounterLoggerLog メソッドを持つインターフェイスです ( と同じシグネチャを持ちます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;

もう少し背景として、これはこの質問の続きです。基本的に、(DCOM) DataSnap サーバーのすべてのメソッドにいくつかのインストルメンテーションを追加しました。また、すべての TDataSnapProvider OnGetData および OnUpdateData イベントにフックしました。

4

2 に答える 2

2

質問の最初の部分を強調して、RegisterLogger と UnregisterLogger の呼び出しはめったにないと述べています。Log 呼び出しはリストを読み取るだけですが、これらの他の 2 つはリストを変更しています。この場合、ログ呼び出しの実行中または発生する可能性がある間は、これらのいずれも実行されないようにする必要があります。

Log の for ループ中に UnregisterLogger の Delete が実行されるとします。結果は少なくとも予測不可能です。

これら 2 つの書き込み呼び出しだけで Synchronizer を使用するだけでは十分ではありません。

だからあなたの質問への答え

TList の読み取りはスレッドセーフですか?

しかありません:それは依存します!

RegisterLogger と UnregisterLogger が発生しないことを確認できる場合 (つまり、読み取り呼び出しのみが発生する可能性がある場合)、安全に Synchronizer を省略できます。そうでなければ - しないほうがいいです。

于 2014-02-24T00:15:24.977 に答える