delphi TNetEncoding.GetBase64Encoding中的潜在竞争条件?

jqjz2hbq  于 12个月前  发布在  其他
关注(0)|答案(1)|浏览(117)

我在 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
  end;
  Result := FBase64Encoding;
end;

字符串
我关心的是这段代码的多线程行为,特别是,在同时执行这个函数的两个线程之间是否存在潜在的竞争条件?
例如,考虑以下场景:

  • 线程1执行AtomicCmpExchange(Pointer(FBase64Encoding), Pointer(LEncoding), nil)
    *线程2到达if FBase64Encoding = nil检查,发现它是假的,表明FBase64Encoding可以使用。但我关心的是,是否保证FBase64Encoding在这一点上是完全有效的。是否有可能线程1的AtomicCmpExchange操作没有完全完成所有数据写入FBase64Encoding?换句话说,线程2可以在检查后立即自信地使用FBase64Encoding吗?或者是否存在访问部分写入的指针的风险?

任何关于此代码是否会导致竞态条件的见解,如果是的话,如何减轻它,将不胜感激。

xdyibdwo

xdyibdwo1#

这段代码是线程安全的。
有可能两个或多个线程将通过nil比较:

if FBase64Encoding = nil then

字符串
在这种情况下,多个线程将构造TBase64Encoding示例并将该示例分配给局部变量LEncoding
但是,只有一个线程会成功地将本地LEncoding变量中的值赋值给FBase64Encoding字段,因为AtomicCmpExchange将原子地执行比较和赋值。这就是AtomicXXX函数的全部目的。
在一个线程将值分配给FBase64Encoding之后,AtomicCmpExchange将对所有其他线程失败(它将返回FBase64Encoding的当前内容,在这种情况下将是非nil值),然后由该线程构建的不需要的编码示例将与LEncoding.Free一起释放。
这段代码的唯一后果是,可能会构造一些额外的编码示例,而那些不需要的编码示例将被立即释放。
如果你在代码中使用这种延迟初始化,你需要注意创建的示例不会占用太多资源,更重要的是,它们可以正确地构造而不会引发异常,而异常可能会对发生异常的线程中的代码产生负面影响。
如果你看一下官方文档,你会发现AtomicCmpExchange以线程安全的方式进行比较和交换。
System.AtomicCmpExchange
原子内部比较和交换函数将Target的内容与给定值(Comparand)进行比较,并且仅当它们相同时,才将Target的内容修改为新值。
此函数始终返回Target的原始值。
AtomicCmpExchange用于比较和交换内存值。
原子操作用于:

  • 实现多线程锁定原语
  • 提供实现所谓的“无锁”结构所必需的原语

相关问题