Is this use of threadvar threadsafe?

Viewed 515

I've got a singleton that can be called by multiple threads.
I do some lookup of data pretty often and I what to cache the data so that I don't have to repeat the same lookup again and again.

I'd like to do something akin to using static local variables, but in a thread-safe way. I suspect the code below is watertight. Is this correct?

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;

I have 2 questions:

A: Am I correct in assuming that managed threadvars like the string FontName are always initialized to Default(T) (i.e. '')

B: Is this code fully threadsafe/ re-entrant?

3 Answers
Related