Delphi Singleton Pattern

18,869

Solution 1

I think if I wanted an object-like thing that didn't have any means of being constructed I'd probably use an interface with the implementing object contained in the implementation section of a unit.

I'd expose the interface by a global function (declared in the interface section). The instance would be tidied up in a finalization section.

To get thread-safety I'd use either a critical section (or equivalent) or possibly carefully implemented double-checked locking but recognising that naive implementations only work due to the strong nature of the x86 memory model.

It would look something like this:

unit uSingleton;

interface

uses
  SyncObjs;

type
  ISingleton = interface
    procedure DoStuff;
  end;

function Singleton: ISingleton;

implementation

type
  TSingleton = class(TInterfacedObject, ISingleton)
  private
    procedure DoStuff;
  end;

{ TSingleton }

procedure TSingleton.DoStuff;
begin
end;

var
  Lock: TCriticalSection;
  _Singleton: ISingleton;

function Singleton: ISingleton;
begin
  Lock.Acquire;
  Try
    if not Assigned(_Singleton) then
      _Singleton := TSingleton.Create;
    Result := _Singleton;
  Finally
    Lock.Release;
  End;
end;

initialization
  Lock := TCriticalSection.Create;

finalization
  Lock.Free;

end.

Solution 2

It was mentioned that i should post my answer from over here.

There is a technique called "Lock-free initialization" that does what you want:

interface

function getInstance: TObject;

implementation

var
   AObject: TObject;

function getInstance: TObject;
var
   newObject: TObject;
begin
   if (AObject = nil) then
   begin
      //The object doesn't exist yet. Create one.
      newObject := TObject.Create;

      //It's possible another thread also created one.
      //Only one of us will be able to set the AObject singleton variable
      if InterlockedCompareExchangePointer(AObject, newObject, nil) <> nil then
      begin
         //The other beat us. Destroy our newly created object and use theirs.
         newObject.Free;
      end;
   end;

   Result := AObject;
end;

The use of InterlockedCompareExchangePointer erects a full memory barrier around the operation. It is possible one might be able to get away with InterlockedCompareExchangePointerAcquire or InterlockedCompareExchangeRelease to get away with an optimization by only having a memory fence before or after. The problem with that is:

  • i'm not smart enough to know if Acquire or Release semantics will work
  • you're constructing an object, the memory barrier performance hit is the least of your worries (it's the thread safety)

InterlockedCompareExchangePointer

Windows didn't add InterlockedCompareExchangePointer until sometime around 2003. In reality it is simply a wrapper around InterlockedCompareExchange

function InterlockedCompareExchangePointer(var Destination: Pointer; Exchange: Pointer; Comparand: Pointer): Pointer stdcall;
const
    SPointerAlignmentError = 'Parameter to InterlockedCompareExchangePointer is not 32-bit aligned';
begin
{IFDEF Debug}
    //On 64-bit systems, the pointer must be aligned to 64-bit boundaries.
    //On 32-bit systems, the pointer must be aligned to 32-bit boundaries.
    if ((NativeInt(Destination) mod 4) <> 0)
            or ((NativeInt(Exchange) mod 4) <> 0)
            or ((NativeInt(Comparand) mod 4) <> 0) then
    begin
        OutputDebugString(SPointerAlignmentError);
        if IsDebuggerPresent then
            Windows.DebugBreak;
    end;
{ENDIF}
    Result := Pointer(IntPtr(InterlockedCompareExchange(Integer(IntPtr(Destination)), IntPtr(Exchange), IntPtr(Comparand))));
end;

In XE6, i find InterlockedcompareExchangePointer implemented for 32-bit in Windows.Winapi implemented the same way (except for the safety checking):

{$IFDEF WIN32}
function InterlockedCompareExchangePointer(var Destination: Pointer; Exchange: Pointer; Comparand: Pointer): Pointer; inline;
begin
  Result := Pointer(IntPtr(InterlockedCompareExchange(Integer(IntPtr(Destination)), IntPtr(Exchange), IntPtr(Comparand))));
end;
{$ENDIF}

In newer versions of Delphi you would, ideally, use the TInterlocked helper class from System.SyncObjs:

if TInterlocked.CompareExchange({var}AObject, newObject, nil) <> nil then
begin
   //The other beat us. Destroy our newly created object and use theirs.
   newObject.Free;
end;

Note: Any code released into public domain. No attribution required.

Solution 3

The trouble with Delphi is that you always inherit the Create constructor from TObject. But we can deal with that pretty nicely! Here's a way:

TTrueSingleton = class
private
  class var FSingle: TTrueSingleton;
  constructor MakeSingleton;
public
  constructor Create;reintroduce;deprecated 'Don''t use this!';

  class function Single: TTrueSingleton;
end;

As you can see we can have a private constructor and we can hide the inherited TObject.Create constructor! In the implementation of TTrueSingleton.Create you can raise an error (run-time block) and the deprecated keyword has the added benefit of providing compile-time error handling!

Here's the implementation part:

constructor TTrueSingleton.Create;
begin
  raise Exception.Create('Don''t call me directly!');
end;

constructor TTrueSingleton.MakeSingleton;
begin
end;

class function TTrueSingleton.Single: TTrueSingleton;
begin
  if not Assigned(FSingle) then FSingle := TTrueSingleton.MakeSingleton;
  Result := FSingle;
end;

If at compile time the compiler sees you doing this:

var X: TTrueSingleton := TTrueSingleton.Create;

it will give you the deprecated warning complete with the provided error message. If you're stubborn enough to ignore it, at run time, you'll not get an object but a raised exception.


Later edit to introduce thread-safety. First of all I must confess, for my own code I don't care about this kind of thread-safety. The probability for two threads accessing my singleton creator routine within such a short time frame it causes two TTrueSingleton objects to be created is so small it's simply not worth the few lines of code required.

But this answer wouldn't be complete without thread safety, so here's my take on the issue. I'll use a simple spin-lock (busy waiting) because it's efficient when no locking needs to be done; Besides, it only locks ones

For this to work an other class var needs to be added: class var FLock: Integer. The Singleton class function should look like this:

class function TTrueSingleton.Single: TTrueSingleton;
var Tmp: TTrueSingleton;
begin
  MemoryBarrier; // Make sure all CPU caches are in sync
  if not Assigned(FSingle) then
  begin
    Assert(NativeUInt(@FLock) mod 4 = 0, 'FLock needs to be alligned to 32 bits.');

    // Busy-wait lock: Not a big problem for a singleton implementation
    repeat
    until InterlockedCompareExchange(FLock, 1, 0) = 0; // if FLock=0 then FLock:=1;
    try
      if not Assigned(FSingle) then
      begin 
        Tmp := TTrueSingleton.MakeSingleton;
        MemoryBarrier; // Second barrier, make sure all CPU caches are in sync.
        FSingle := Tmp; // Make sure the object is fully created when we assign it to FSingle.
      end;
    finally FLock := 0; // Release lock
    end;
  end;
  Result := FSingle;
end;

Solution 4

There is a way to hide the inherited “Create” constructor of TObject. Although it is not possible to change the access level, it can be hidden with another public parameterless method with the same name: “Create”. This simplifies the implementation of the Singleton class tremendously. See the simplicity of the code:

unit Singleton;

interface

type
  TSingleton = class
  private
    class var _instance: TSingleton;
  public
    //Global point of access to the unique instance
    class function Create: TSingleton;

    destructor Destroy; override;
  end;

implementation

{ TSingleton }

class function TSingleton.Create: TSingleton;
begin
  if (_instance = nil) then
    _instance:= inherited Create as Self;

  result:= _instance;
end;

destructor TSingleton.Destroy;
begin
  _instance:= nil;
  inherited;
end;

end.

I added the details to my original post: http://www.yanniel.info/2010/10/singleton-pattern-delphi.html

Solution 5

The most effective way to make sure something cannot be instantiated is by making it a pure abstract class. That is, if you care enough to heed compiler hints and warnings.

Then define a function in the implementation section that returns a reference to that abstract class. Like Cosmin does in one of his answers.

The implementation section implements that function (you can even make use of lazy instantiation here, as Cosmin also shows/ed).

But the crux is to have a concrete class declared and implemented in the implementation section of the unit so only the unit can instantiated it.

interface

type
  TSingleton = class(TObject)
  public
    procedure SomeMethod; virtual; abstract;
  end;

  function Singleton: TSingleton;

implementation

var
  _InstanceLock: TCriticalSection;
  _SingletonInstance: TSingleTon;

type
  TConcreteSingleton = class(TSingleton)
  public
    procedure SomeMethod; override;
  end;

function Singleton: TSingleton;
begin
  _InstanceLock.Enter;
  try
    if not Assigned(_SingletonInstance) then
      _SingletonInstance := TConcreteSingleton.Create;

    Result := _SingletonInstance;
  finally
    _InstanceLock.Leave;
  end;
end;

procedure TConcreteSingleton.SomeMethod;
begin
  // FLock can be any synchronisation primitive you like and should of course be
  // instantiated in TConcreteSingleton's constructor and freed in its destructor.
  FLock.Enter;  
  try
  finally
    FLock.Leave;
  end;
end;

That said, please bear in mind that there are plenty of problems using singletons: http://jalf.dk/blog/2010/03/singletons-solving-problems-you-didnt-know-you-never-had-since-1995/

Thread safety

David is absolutely right in his comment that I was wrong before about the function not needing any protection. The instantiation does indeed need protecting or you could end up with two (possibly more) instances of the singleton and several of them in limbo with regard to freeing (which would be done in the finalization section as with many lazy instantion mechanisms). So here is the amended version.

To get thread safety in this setup, you need to protect the instantiation of the singleton and you need to protect all methods in the concrete class that are publicly available through its abstract ancestor. Other methods do not need to be protected as they are only be callable through the publicly available ones and so are protected by the protection in those methods.

You can protect this by a simple critical section, declared in the implementation, instantiated in the initialization and free in the finalization section. Of course the CS would have to protect the freeing of the singleton as well and should therefore be freed afterwards.

Discussing this with a colleague, we came up with a way to (mis)/(ab)use the instance pointer itself as a sort of lock mechanism. It would work, but I find it to ugly to share with the world at this point in time...

What synchronisation primitives are used to protect the publicly callable methods is entirely up to the "user" (coder) and may tailored to the purpose the singleton.

Share:
18,869

Related videos on Youtube

elector
Author by

elector

Updated on May 05, 2020

Comments

  • elector
    elector almost 4 years

    I know this is discussed many times everywhere i the community but I just can't find a nice and simple implementation of a Singleton Pattern in Delphi. I have an example in C#:

    public sealed class Singleton {
      // Private Constructor
      Singleton() { }
    
      // Private object instantiated with private constructor
      static readonly Singleton instance = new Singleton();
    
      // Public static property to get the object
      public static Singleton UniqueInstance {
        get { return instance; }
      }
    }
    

    I know there is no solution as elegant as this in Delphi and I saw a lot of discussion about no being able to correctly hide the constructor in Delphi (make it private) so we would need to override the NewInstance and FreeInstance methods. Something along those lines I believe is the implementation I found on ibeblog.com - "Delphi: Singleton Patterns":

    type
      TTestClass = class
      private
        class var FInstance: TTestClass;
      public                              
        class function GetInstance: TTestClass;
        class destructor DestroyClass;
      end;
    
    { TTestClass }
    class destructor TTestClass.DestroyClass;
    begin
      if Assigned(FInstance) then
        FInstance.Free;
    end;
    
    class function TTestClass.GetInstance: TTestClass;
    begin
      if not Assigned(FInstance) then
        FInstance := TTestClass.Create;
      Result := FInstance;
    end;
    

    What would be your suggestion regarding the Singleton Pattern? Can it be simple and elegant and thread safe?

    Thank you.

    • David Heffernan
      David Heffernan about 13 years
      Are you sure that the C# one is thread-safe? It seems different from Mr. Skeet's version?
    • mjn
      mjn about 13 years
      Mr Skeet's fourth version is thread safe and looks almost the same, except for a static constructor to enhance 'lazyness'
    • David Heffernan
      David Heffernan about 13 years
      @mjn If it was me, I would just do whatever the great man says!!
  • David Heffernan
    David Heffernan about 13 years
    Where's the thread-safety? This is down-vote bait.
  • David Heffernan
    David Heffernan about 13 years
    I'm not seeing any thread-safety.
  • Cosmin Prund
    Cosmin Prund about 13 years
    @Marjan Venema, I deleted both my answers when I realized the OP isn't looking for examples of singleton implementations (mrr, need to read questions twice before answering); The OP apparently wants a way of handling the inability to hide TObject.Create. At least that's how I understand this: "I saw a lot of discussion about no being able to correctly hide the constructor". Besides the OP is actually providing an example of singleton implementation in the question!
  • Marjan Venema
    Marjan Venema about 13 years
    @David: Because that would have to be in the concrete class's implementation of its methods, at least the ones that can be used from the outside through its abstract ancestor. It's no use putting any synchronisation primitives in the implementation of the function returning the instance, as that would only protect getting the reference, nothing else.
  • David Heffernan
    David Heffernan about 13 years
    @marjan No, you need to protect getting the reference too. Otherwise you can end up with more than one of them.
  • Cosmin Prund
    Cosmin Prund about 13 years
    @Marjan Venema, there's a big talk lately about the simple "if not Assigned(F) then F := Something` kind of code in threaded applications, because that can't be used without proper locking. That construct is usually used in the constructors of singletons. Myself I don't care, my singletons are created using the mentioned construct, but of course for those answers we'll need to provide proper locking.
  • David Heffernan
    David Heffernan about 13 years
    Sorry, I had to downvote because the edit regarding thread safety is plain wrong. The whole point of the question's C# code is to ensure that only one singleton can be created. If the singleton is a const object, in C++ terms, then it needs no internal locking, but the reference getting code needs locking.
  • Marjan Venema
    Marjan Venema about 13 years
    @David, yes, I can see what you mean. thinking....
  • Daniel Maurić
    Daniel Maurić about 13 years
    +1 Was about to post pretty much that exact code
  • David Heffernan
    David Heffernan about 13 years
    @Daniel Once you have the idea, there's really only one way to write it!!
  • Marjan Venema
    Marjan Venema about 13 years
    Yep, the interfaced version. But I would not free the lock before freeing the _Singleton. I would enter the lock, free the singleton, the leave and free the lock.
  • Cosmin Prund
    Cosmin Prund about 13 years
    You're entering the critical section every time you read the value of _Singleton. Is that expense required?
  • David Heffernan
    David Heffernan about 13 years
    @Cosmin To avoid it you need double-checked locking which is difficult to get right and only works due to x86's memory model being strong. If you can live with the expense (perhaps by caching a copy of the interface) then it makes the code much simpler.
  • David Heffernan
    David Heffernan about 13 years
    @Marjan finalization code runs single threaded, so doesn't matter what order you do things.
  • David Heffernan
    David Heffernan about 13 years
    Cardinal(@FLock)?! Surely you mean NativeUInt!
  • Cosmin Prund
    Cosmin Prund about 13 years
    @David, why live with that expense when you can be without it? My synchronization avoids the double-lock traps and only locks if the singleton hasn't been initialized, so it can be done.
  • Daniel Maurić
    Daniel Maurić about 13 years
    If you precreate the singleton in Initialization then you don't even need locking
  • Cosmin Prund
    Cosmin Prund about 13 years
    @David no, why would I? First of all I'll cross the 64 bit bridge when I get there, and on the 64 bit platform I'm not sure I need a 64bit variable for the lock.
  • David Heffernan
    David Heffernan about 13 years
    @Daniel Precreation is clearly best if it can be done. However, OP's question clearly suggests lazy initialization.
  • David Heffernan
    David Heffernan about 13 years
    @Cosmin That's fine, but if you don't need the complexity, and often you don't, then a simple lock is easy to validate in terms of correctness. I always favour locks if they don't harm performance because it is easy to be sure that they are correct.
  • David Heffernan
    David Heffernan about 13 years
    @Cosmin Finally, your code only avoids double-checked locking traps if it runs on a platform with a strong memory model. Fine for x86, but in the future, who knows?
  • jachguate
    jachguate about 13 years
    @Cosmin, you're casting the pointer, not the value... I'm with David, better if you use NativeUInt, because that's the pointer size. :)
  • Cosmin Prund
    Cosmin Prund about 13 years
    @David, paying a performance penalty today just in case Delphi starts compiling for non-x86, non-x64 platforms some day, in the (very) distant future, doesn't seem right. Now that Itanium is dead, I don't even know what platform that might be. It'll have to be invented first! And with so many unknowns, I don't think using a TCriticalSection will be enough any way.
  • David Heffernan
    David Heffernan about 13 years
    @Cosmin Critical section is guaranteed to work. That's part of its contract. Have you read The "Double-Checked Locking is Broken" Declaration? Anyway, the big idea here is to use an interface. The locking/thread-safety implementation can be done many ways. I've illustrated one and proposed another. You have yet another. The main idea is the interface.
  • Sertac Akyuz
    Sertac Akyuz about 13 years
    @jachguate - Wrong, InterlockedCompareExchange compares two 32-bit longs, see the documentation. NativeUInt will work for not but won't compile with 64-bit.
  • jachguate
    jachguate about 13 years
    @Sertac I'm not talking about FLock type, but about pointer type cast, and @Cosmin already edited the code to change as originally suggested by @David.
  • jachguate
    jachguate about 13 years
    Interesting, the documentation link from @Sertac states: To operate on 64-bit values, use the InterlockedCompareExchange64 function., so it must have to be adapted to the win64 bit platform anyway.
  • Sertac Akyuz
    Sertac Akyuz about 13 years
    @jachguate - Ah, Ok, sorry.. Thanks.
  • Marjan Venema
    Marjan Venema about 13 years
    @David: while finalization code may run single threaded, that doesn't necessarily mean all threads have finished...
  • Cosmin Prund
    Cosmin Prund about 13 years
    @jachugate, don't be sorry, you were right, Sertac's wrong. That Assertion is about checking rather the address of FLock is aligned on 32 bits, has nothing to do with the type of FLock or the Interlocked function to be called. That's why I changed it to NativeUInt! And of course Sertac is right about the InterlockedCompareExchange64, that's what I meant when I said I'll cross the 64 bit bridge when I get there.
  • David Heffernan
    David Heffernan about 13 years
    @Marjan Every program I know stops all worker threads before running finalization.
  • Marjan Venema
    Marjan Venema about 13 years
    @David: Then you are lucky... :) Callbacks can make life a lot harder...
  • David Heffernan
    David Heffernan about 13 years
    @Marjan That's no luck, that's design!! ;-)
  • Marjan Venema
    Marjan Venema about 13 years
    @David: Not always when working with third party components, libraries, WIN API calls and call backs into separate threads. And working under performance constraints to do the minimum locking possible...
  • Marjan Venema
    Marjan Venema about 13 years
    @David: not to mention design decisions from the past coming back to bite you in the behind... ;-)
  • mistertodd
    mistertodd almost 10 years
    See also `InterlockedCompareExchangePointer, which is 64/32 bits as appropriate, and required 8-byte/4-byte alignment as appropriate.
  • truthseeker
    truthseeker about 9 years
    Nice clean solution. No unneccesary locking or memory barriers if object was created long time ago. Thanks.
  • Rohit Gupta
    Rohit Gupta almost 9 years
    @CosminPrund. This is a good solution. But with the interfaces being here, I think David's solution trumps it. I wish I had thought of it in 2000.
  • Shannon Matthews
    Shannon Matthews over 8 years
    Where is InterlockedCompareExchangePointer() declared?
  • mistertodd
    mistertodd over 8 years
    @Shannon In newer versions of Delphi it's declared in Windows.Winapi. In Delphi 5 had to write it myself; as a wrapper around InterlockedCompareExchange. Updated answer with version of InterlockedcompareExchange for 32-bit.
  • Shannon Matthews
    Shannon Matthews over 8 years
    Thanks for the extra info Ian.
  • EProgrammerNotFound
    EProgrammerNotFound over 8 years
    This is the coolest approach, IMO.
  • Rudy Velthuis
    Rudy Velthuis over 6 years
    @David: That looks a lot like this one: stackoverflow.com/a/1409672/95954
  • Delmo
    Delmo over 5 years
    @MarjanVenema That's more or less the same idea David described on his answer. Your abstract class would be the David's interface (ISingleton), your concrete class would be the David's class (TSingleton). Using the David's solution, the singlenton will be destroyed automatically but you didn't show how to do so in your solution.