在C#中,以下代码(来自 这个 页面)可用于以线程安全的方式懒惰地实例化singleton课程:

  class Foo {
        private volatile Helper helper = null;
        public Helper getHelper() {
            if (helper == null) {
                lock(this) {
                    if (helper == null)
                        helper = new Helper();
                }
            }
            return helper;
        }
    }

等效线程安全Delphi代码是什么?


本文还提到了在Java中进行双检查锁定的两个问题:

  • 在向助手引用指向新创建的对象之前,可能会构造新对象,这意味着创建了两个对象
  • 当对象仍在创建对象时,可能会将辅助引用指向内存的块,这意味着将返回对不完整对象的引用

因此,尽管上述文章中的C#和Java版本的代码几乎相同,但只有C#版本可以按预期工作。哪个问题是否也导致了这两个问题是否在Delphi版本的双检查锁定中也存在?

有帮助吗?

解决方案

使用system.tmonitor以线程安全方式锁定对象实例。

function TFoo.GetHelper(): THelper;
begin
  if not Assigned(FHelper) then
  begin
    System.MonitorEnter(Self);
    try
      if not Assigned(FHelper) then
        FHelper := THelper.Create();
    finally
      System.MonitorExit(Self);
    end;
  end;
  Result := FHelper;
end;

要进一步参考 锁定我的对象...请!艾伦·鲍尔(Allen Bauer). 。实际上,代表。我从中聚集应该去艾伦。

其他提示

当然,总是值得记住 双检查的锁定损坏. 。事实证明,这个问题不适用于X86内存模型,但始终值得牢记未来。我敢肯定,在某个时候将有Delphi版本,该版本将在带有此问题折磨的内存模型的平台上运行。

Embarcadero已开始使用此模式的无锁版本与互锁/交换。例如:

class function TEncoding.GetUnicode: TEncoding;
var
  LEncoding: TEncoding;
begin
  if FUnicodeEncoding = nil then
  begin
    LEncoding := TUnicodeEncoding.Create;
    if InterlockedCompareExchangePointer(Pointer(FUnicodeEncoding), LEncoding, nil) <> nil then
      LEncoding.Free;
  end;
  Result := FUnicodeEncoding;
end;

我意识到这不是问题的答案,但它并不真正适合评论!

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top