这是使用threadvar线程安全吗?

Joh*_*ica 6 delphi string thread-safety

我有一个可以被多个线程调用的单例.
我经常查找一些数据,然后我要缓存数据,这样我就不必一次又一次地重复相同的查找.

我想做一些类似于使用静态局部变量的东西,但是以线程安全的方式.我怀疑下面的代码是不漏水的.它是否正确?

type
  TPrevious = record
  public
    Fontname: string;
    FontSize: integer;
    Canvas: pointer;
    Width: integer;
  end;

threadvar Previous: TPrevious;

function TEditorOptions.GetEditorFontWidth(const Canvas: TCanvas): integer;
var
  Font: TFont;
//var  //static vars            <<-- static var != threadsafe
//  PreviousFontName: string = '';
//  PreviousFontSize: integer = 0;
//  PreviousCanvas: pointer = nil;
//  PreviousWidth: integer = 0;
begin
  {1: I'm assuming a managed threadvar is always initialized to Default(T)}
  if (Previous.Fontname <> '') then begin
      //Cache the values, so we don't recalculate all the time.
      //Caching is per thread, but that's fine.
    if (SameText(Previous.FontName, FFontName)) and (Previous.FontSize = FFontSize)
       and (pointer(Canvas) = Previous.Canvas) then Exit(Previous.Width);
  end;
  Previous.Canvas := pointer(Canvas);
  Previous.FontName := FFontName;
  Previous.FontSize := FFontSize;
  Result:= SomeCalculation(Canvas, FFontName, FFontSize);
  ....
    Previous.Width:= Result;
  ....
end;
Run Code Online (Sandbox Code Playgroud)

我有两个问题:

答:假设像字符串这样的托管threadvars FontName总是初始化为Default(T)(即'') ,我是否正确

B:这段代码是完全线程安全/可重入吗?

Arn*_*hez 5

  1. 任何threadvar实例都填充为零,因此您的string变量已正确初始化.

  2. 遗憾的是,threadvar不要处理其托管类型的内存...因此,您需要释放变量中的每个string内容Previous.

  3. 实际上,我不在threadvar中存储托管类型,而是使用另一种模式(比如构造函数级别的注入).

  4. Previous.xxxxx的性能损失:访问每个成员有一个性能成本:您可能更喜欢填充局部变量指针@Previous,然后使用此指针访问字段(或使用with Previous do- 但这种语法可能会令人困惑).