带有 Delphi 字符串的 InterlockedCompareExchangePointer
InterlockedCompareExchangePointer with Delphi string
在我的服务器代码中,我使用以下模式创建“及时”对象:
function TSomeObject.GetChildObjects: TChildObjects;
var
ChildObjects: TChildObjects;
begin
if FChildObjects=nil then
begin
ChildObjects:=TChildObjects.Create;
// Fill child objects here
if InterlockedCompareExchangePointer(Pointer(FChildObjects),ChildObjects,nil) <> nil then
ChildObjects.Free;
end;
result:=FChildObjects;
end;
这很好用,但我如何用 Delphi 字符串做类似的事情?例如如果我想在多线程环境中“及时”初始化一个字符串?还是我必须使用关键部分?例如:
function TSomeObject.GetSomeString: string;
var
s :string;
begin
if FSomeString='' then
begin
s:='Test';
// InterlockedCompareExchangePointer(Pointer(FSomeString),s,nil);
end;
result:=FSomeString;
end;
字符串是引用计数的,所以仅仅交换指针是不够的,你还必须管理引用计数,例如:
function GetStrRec(const S: string): PStrRec; inline;
begin
Result := PStrRec(PByte(S) - SizeOf(StrRec));
end;
function InterlockedCompareExchangeString(var VTarget: String; const AValue, Compare: String): String; inline;
var
P: PStrRec;
begin
Result := '';
if AValue <> '' then begin
P := GetStrRec(AValue);
if P.refCnt > -1 then AtomicIncrement(P.refCnt);
end;
Pointer(Result) := InterlockedCompareExchangePointer(Pointer(VTarget), Pointer(AValue), Pointer(Compare));
if Pointer(Result) <> Pointer(Compare) then begin
if Result <> '' then begin
P := GetStrRec(Result);
if P.refCnt > -1 then AtomicIncrement(P.refCnt);
end;
if AValue <> '' then begin
P := GetStrRec(AValue);
if P.refCnt > -1 then AtomicDecrement(P.refCnt);
end;
end;
end;
或者:
function GetStrRec(const S: string): PStrRec; inline;
begin
Result := PStrRec(PByte(S) - SizeOf(StrRec));
end;
function InterlockedCompareExchangeString(var VTarget: String; const AValue, Compare: String): String; inline;
var
P: PStrRec;
begin
Result := '';
Pointer(Result) := InterlockedCompareExchangePointer(Pointer(VTarget), Pointer(AValue), Pointer(Compare));
if Pointer(Result) = Pointer(Comparand) then
begin
if AValue <> '' then begin
P := GetStrRec(AValue);
if P.refCnt > -1 then AtomicIncrement(P.refCnt);
end;
end
else if Result <> '' then begin
P := GetStrRec(Result);
if P.refCnt > -1 then AtomicIncrement(P.refCnt);
end;
end;
不幸的是,RTL 没有公开函数来操作字符串的引用计数,只能查询它(StringRefCount()
), which is why you have to access and manipulate the string's inner StrRec
header 手动。
在我的服务器代码中,我使用以下模式创建“及时”对象:
function TSomeObject.GetChildObjects: TChildObjects;
var
ChildObjects: TChildObjects;
begin
if FChildObjects=nil then
begin
ChildObjects:=TChildObjects.Create;
// Fill child objects here
if InterlockedCompareExchangePointer(Pointer(FChildObjects),ChildObjects,nil) <> nil then
ChildObjects.Free;
end;
result:=FChildObjects;
end;
这很好用,但我如何用 Delphi 字符串做类似的事情?例如如果我想在多线程环境中“及时”初始化一个字符串?还是我必须使用关键部分?例如:
function TSomeObject.GetSomeString: string;
var
s :string;
begin
if FSomeString='' then
begin
s:='Test';
// InterlockedCompareExchangePointer(Pointer(FSomeString),s,nil);
end;
result:=FSomeString;
end;
字符串是引用计数的,所以仅仅交换指针是不够的,你还必须管理引用计数,例如:
function GetStrRec(const S: string): PStrRec; inline;
begin
Result := PStrRec(PByte(S) - SizeOf(StrRec));
end;
function InterlockedCompareExchangeString(var VTarget: String; const AValue, Compare: String): String; inline;
var
P: PStrRec;
begin
Result := '';
if AValue <> '' then begin
P := GetStrRec(AValue);
if P.refCnt > -1 then AtomicIncrement(P.refCnt);
end;
Pointer(Result) := InterlockedCompareExchangePointer(Pointer(VTarget), Pointer(AValue), Pointer(Compare));
if Pointer(Result) <> Pointer(Compare) then begin
if Result <> '' then begin
P := GetStrRec(Result);
if P.refCnt > -1 then AtomicIncrement(P.refCnt);
end;
if AValue <> '' then begin
P := GetStrRec(AValue);
if P.refCnt > -1 then AtomicDecrement(P.refCnt);
end;
end;
end;
或者:
function GetStrRec(const S: string): PStrRec; inline;
begin
Result := PStrRec(PByte(S) - SizeOf(StrRec));
end;
function InterlockedCompareExchangeString(var VTarget: String; const AValue, Compare: String): String; inline;
var
P: PStrRec;
begin
Result := '';
Pointer(Result) := InterlockedCompareExchangePointer(Pointer(VTarget), Pointer(AValue), Pointer(Compare));
if Pointer(Result) = Pointer(Comparand) then
begin
if AValue <> '' then begin
P := GetStrRec(AValue);
if P.refCnt > -1 then AtomicIncrement(P.refCnt);
end;
end
else if Result <> '' then begin
P := GetStrRec(Result);
if P.refCnt > -1 then AtomicIncrement(P.refCnt);
end;
end;
不幸的是,RTL 没有公开函数来操作字符串的引用计数,只能查询它(StringRefCount()
), which is why you have to access and manipulate the string's inner StrRec
header 手动。