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:这段代码是完全线程安全/可重入吗?
任何threadvar实例都填充为零,因此您的string变量已正确初始化.
遗憾的是,threadvar不要处理其托管类型的内存...因此,您需要释放变量中的每个string内容Previous.
实际上,我不在threadvar中存储托管类型,而是使用另一种模式(比如构造函数级别的注入).
小Previous.xxxxx的性能损失:访问每个成员有一个性能成本:您可能更喜欢填充局部变量指针@Previous,然后使用此指针访问字段(或使用with Previous do- 但这种语法可能会令人困惑).