“双重检查锁定”应该如何使用?在Delphi中实现?

发布于 2024-10-08 19:27:56 字数 751 浏览 1 评论 0原文

在 C# 中,以下代码(来自页面)可用于延迟实例化单例线程安全的类:

  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 版本的双重检查锁定中,这会导致额外的问题吗?

In C#, the following code (from this page) can be used to lazily instantiate a singleton class in a thread safe way:

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

What would be the equivalent thread safe Delphi code?


The article also mentions two problems with Double Checked Locking in Java:

  • it is possible that the new object is constructed before the helper reference is made to point at the newly created object meaning that two objects are created
  • it is possible that the helper reference is made to point at a block of memory while the object is still being created meaning that a reference to an incomplete object will be returned

So while the code of the C# and the Java version in the mentioned article look almost identical, only the C# version works as expected. Which leads to the additional question if these two problems also exist in a Delphi version of Double-Checked Locking?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

暗恋未遂 2024-10-15 19:27:56

使用 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;

如需进一步参考,请参阅请锁定我的对象...!来自艾伦·鲍尔。事实上,代表。我由此推断应该去艾伦那里。

Use System.TMonitor to lock the object instance in a thread safe way.

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;

For further reference look at Lock my object..., please! from Allen Bauer. In fact, the rep. I gather from this should go to Allen.

探春 2024-10-15 19:27:56

当然,始终值得记住双重检查锁定已损坏。事实证明,这个问题并不适用于 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;

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

Of course, it's always worth remembering that Double-Checked Locking is Broken. This issue turns out not to apply to the x86 memory model but it's always worth bearing in mind for the future. I'm sure there will be Delphi version at some point that will run on a platform with a memory model that is afflicted by this issue.

Embarcadero have started using a lock-free version of this pattern with interlocked compare/exchange. For example:

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;

I realise this isn't an answer to the question but it didn't really fit in a comment!

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文