我有一个懒惰的创建情况,一个(单例)对象只在需要它的代码执行时才被创建。这是在ISAPI dll的上下文中操作的,它是多线程的,所以存在两个线程可以访问它的风险。
我的代码最初看起来像这样,非常天真:
...
interface
var
FHIRResourceFactory: function: IFHIRResourceFactory;
implementation
...
// global var and function
var
_FHIRFactory: IFHIRResourceFactory;
function GetFHIRResourceFactory: IFHIRResourceFactory;
begin
if (_FHIRFactory = nil) then
{ The object doesn't exist yet. Create one. }
_FHIRFactory := TFHIRResourceFactory.Create;
Result := _FHIRFactory;
end;
initialization
FHIRResourceFactory := GetFHIRResourceFactory;
end.
我重构了它以使用AtomicCmpExchange()
,但我发现创建的对象福尔斯了范围:
...
interface
var
FHIRResourceFactory: function: IFHIRResourceFactory;
implementation
...
// global var and function
var
_FHIRFactory: IFHIRResourceFactory;
function GetFHIRResourceFactory: IFHIRResourceFactory;
var
newFHIRFactory: IFHIRResourceFactory;
begin
if (_FHIRFactory = nil) then
begin
{ The object doesn't exist yet. Create one. }
newFHIRFactory := TFHIRResourceFactory.Create;
{ It's possible another thread also created one.
Only one of us will be able to set the _FHIRFactory singleton variable }
if AtomicCmpExchange(Pointer(_FHIRFactory), Pointer(newFHIRFactory), nil) <>= nil then
begin
{ The other beat us. Destroy our newly created object and use theirs. }
newFHIRFactory := nil;
end;
// if I don't add this line the object will fall out of scope and be destroyed
// _FHIRFactory._AddRef
end;
Result := _FHIRFactory;
end;
initialization
FHIRResourceFactory := GetFHIRResourceFactory;
end.
是否有一个版本的TInterlocked.CompareExchange()
可以接受接口对象?
1条答案
按热度按时间goucqfw61#
不幸的是,
TInterlocked
* 不 * 支持处理引用计数接口(奇怪的是,它的TObject
方法 * 在ARC系统下处理引用计数对象)。因此,您必须手动管理接口引用计数。例如,这是Indy使用的函数:
(其中
InterlockedCompareExchangePtr()
是各种特定于平台的函数的 Package 器,包括可用的TInterlocked.CompareExchange()
)您可以用已经使用的
AtomicCmpExchange()
或TInterlocked.CompareExchange()
的Pointer
重载替换InterlockedCompareExchangePtr()
。例如:
如果
_FHIRFactory
被设置为新对象,则其recount将递增为2,然后在newFHIRFactory
超出范围时递减为1,从而使对象保持活动状态。如果
_FHIRFactory
没有被设置为新对象,它的recount将增加到2,然后返回到1,然后当newFHIRFactory
超出范围时减少到0,从而销毁对象。