Multithreading Aquire单例类实例多线程

Multithreading Aquire单例类实例多线程,multithreading,delphi,synchronization,singleton,delphi-6,Multithreading,Delphi,Synchronization,Singleton,Delphi 6,要获取具有Singleton模式的类的实例,我希望使用以下函数: 这是一幅草图 interface uses SyncObjs; type TMCriticalSection = class(TCriticalSection) private Dummy : array [0..95] of Byte; end; var InstanceNumber : Integer; AObject: TObject; CriticalSection: TMCritic

要获取具有Singleton模式的类的实例,我希望使用以下函数:

这是一幅草图

interface

uses SyncObjs;

type
  TMCriticalSection = class(TCriticalSection)
  private
    Dummy : array [0..95] of Byte;
  end;

var
  InstanceNumber : Integer;
  AObject: TObject;
  CriticalSection: TMCriticalSection;

function getInstance: TObject;

implementation

uses Windows;

function getInstance: TObject;
begin
   //I Want somehow use InterlockedCompareExchange instead of CriticalSession, for example

   if InterlockedCompareExchange(InstanceNumber, 1, 0) > 0 then
   begin
     Result := AObject;
   end
   else
   begin
      CriticalSection.Enter;
      try
        AObject := TObject.Create;
      finally
        CriticalSection.Leave;
      end;
      InterlockedIncrement(InstanceNumber);
      Result := AObject
   end;
end;

initialization
  CriticalSection := TMCriticalSection.Create;
  InstanceNumber := 0;

finalization;
  CriticalSection.Free;

end.
三个问题:

1-这种设计是线程安全的吗?特别是带有联锁交换部件的
2-如何使用InterloctedCompareeExchange?有可能做我正在尝试的事情吗
3-该设计是否比包含关键部分范围内的所有代码更好

备注: 我的对象是线程安全的,只有我需要序列化的结构
这不是intire代码,只是重要的部分,我的意思是getInstance函数。

编辑 我需要使用某种单例对象
如果InstanceNumber的值为零,是否有任何方法可以使用InterlocatedCompareeExchange进行比较

1-仅当值为0时创建对象,否则返回实例
2-当值为0时:在关键部分输入。创建对象。离开临界区

3-这样做会更好,而不是将所有代码都包含在关键部分范围内?

您的设计不起作用,即使不了解
InterlocatedCompareeExchange
的功能,也可以看到这一点。事实上,不管
InterlocatedCompareeExchange
的含义是什么,您的代码都被破坏了

参见此,考虑两个线程同时到达<代码> < <代码> >语句,同时在代码> GETSimule< /代码>。让我们考虑他们所采用的分支的三个选项:

  • 他们都选择了第二个分支。然后创建两个实例,代码不再实现单例
  • 他们都选择了第一个分支。那么你永远不会创建一个实例
  • 一个选择第一个,另一个选择第二个。但是由于第一个分支中没有锁,因此采用该路由的线程可以在另一个线程写入它之前读取
    aoobject

  • 就我个人而言,如果我必须实现您的
    getInstance
    函数,我会使用它。

    有一种技术可以满足您的需要:

    接口
    函数getInstance:TObject;
    实施
    变量
    a对象:对象;
    函数getInstance:TObject;
    变量
    新对象:TObject;
    开始
    如果(AObject=nil),则
    开始
    //对象还不存在。创建一个。
    newObject:=TObject.Create;
    //有可能是另一个线程也创建了一个。
    //我们中只有一个人能够设置AOObject单例变量
    如果InterlocatedCompareeExchangePointer(AOObject,newObject,nil)为nil,则
    开始
    //另一个打败了我们。销毁我们新创建的对象并使用它们。
    newObject.Free;
    结束;
    结束;
    结果:=A对象;
    结束;
    
    使用
    InterlocatedCompareeExchangePointer
    会在操作周围建立一个完整的内存屏障。使用发布语义(以确保在执行比较交换之前完成对象的构造),可能不需要
    InterlocatedCompareExchangeRelease
    。问题是:

    • 我不够聪明,不知道仅仅发布语义是否真的有效(只是因为一个比我更聪明的人说他们会,并不意味着我知道他在说什么)
    • 在构建一个对象时,内存障碍性能的影响是您最不担心的(这是线程安全)
    注意:发布到公共域的任何代码。无需归因


    是的,你是对的,我对使用InterlocatedCompare感到非常兴奋,甚至没有意识到这一点。谢谢,最好的方法是将所有代码放在关键部分上下文中,对吗?您可以使用双重检查锁定,它在Delphi的x86/x64上运行。我在我的答案中添加了一个链接到另一个答案(我的一个),这个链接更详细地介绍了这个主题。这个怎么样?阅读我链接到的答案。从本质上讲,x86和x64内存模型是强大的,而Delphi并没有优化从全局变量到寄存器的读/写操作。所以,DCL在Delphi的x86/x64+1上工作,它看起来很轻……您研究过重新排序的可能性吗?这是免费的吗?这正是我想要的。你也应该在这里添加你的答案:@eprogrammernot发现它是内存安全的,因为
    interloctedcompareeexchangepointer
    设置了一个完整的内存屏障。完全是,但我太胆小了。