在delphi源代码中,我们有:
class function TNetEncoding.GetBase64Encoding: TNetEncoding;
var
LEncoding: TBase64Encoding;
begin
if FBase64Encoding = nil then
begin
LEncoding := TBase64Encoding.Create;
if AtomicCmpExchange(Pointer(FBase64Encoding), Pointer(LEncoding), nil) <> nil then
LEncoding.Free
{$IFDEF AUTOREFCOUNT}
else
FBase64Encoding.__ObjAddRef
{$ENDIF AUTOREFCOUNT};
end;
Result := FBase64Encoding;
end;但我不明白,它们混合了原子操作 (AtomicCmpExchange(Pointer(FBase64Encoding), Pointer(LEncoding), nil)和非原子操作,如if FBase64Encoding = nil then和Result := FBase64Encoding; )
这不是个错误吗?
发布于 2019-01-09 08:39:56
在注释中,您清楚地表明,您所关心的是不受保护的内存操作可能会被撕毁。撕裂是指读取线程在部分写入变量时读取它。
这在一般情况下是合理的,但在这种情况下不可能发生撕裂。其原因是,对齐内存访问保证不会被撕破。当内存操作对齐时,读取器无法读取部分写入的变量。这通常是通过硬件总线序列化单个缓存行中的所有内存访问来保证的。
所以,不,这不是一个错误,代码是正确的。
代码本身习惯于懒洋洋地创建单例程序。采用线程安全方式这样做的一种常见技术是双重检查锁定。此代码使用一种避免锁定的替代技术。相反,代码可能允许多个线程推测地创建单例。如果多个线程成功地创建了对象,那么成功的第一个线程将获胜,而其他线程将销毁它们的实例并使用winner线程创建的实例。
如果创建附加实例然后销毁它们是良性的,则无锁方法工作得很好。但情况并非总是如此。例如,创建实例的多个副本可能过于昂贵。在这种情况下,基于锁的方法更好。
https://stackoverflow.com/questions/54104882
复制相似问题