3

I want to implement a singleton critical section in order to protect some code across several classes(don't ask further...). I've seen Delphi Singleton Pattern and Aquire Singleton class Instance Multithread but these are using a global function to return the singleton and I don't want that. So, I've implemented my own version:

unit SynchronizationHandler;

interface

uses
  SyncObjs;

type
  TSynchronizationHandler = class
  strict private
    FCriticalSection: TCriticalSection;
  private
    class var FSingletonCriticalSection: TCriticalSection;
    class var FInstance: TSynchronizationHandler;
  public
    constructor Create;
    destructor Destroy; override;

    procedure Lock;
    procedure Release;
    class function Instance: TSynchronizationHandler;
  end;

implementation

{ TSynchronizationHandler }

constructor TSynchronizationHandler.Create;
begin
  FCriticalSection := TCriticalSection.Create;
end;

destructor TSynchronizationHandler.Destroy;
begin
  FCriticalSection.Destroy;
end;

{Doublec check locking for this singletone}
class function TSynchronizationHandler.Instance: TSynchronizationHandler;
begin
  if not Assigned(FInstance) then
   begin
    FSingletonCriticalSection.Acquire;
    try
      if not Assigned(FInstance) then
        FInstance := TSynchronizationHandler.Create;
    finally
      FSingletonCriticalSection.Release;
    end;
  end;

  Result := FInstance;
end;

procedure TSynchronizationHandler.Lock;
begin
  FCriticalSection.Acquire;
end;

procedure TSynchronizationHandler.Release;
begin
  FCriticalSection.Release;
end;

initialization
  TSynchronizationHandler.FSingletonCriticalSection := TCriticalSection.Create;

finalization
  if Assigned(TSynchronizationHandler.FInstance) then
    TSynchronizationHandler.Instance.Free;

  TSynchronizationHandler.FSingletonCriticalSection.Free;

end.

It's working but I don't like the initialization\finalization part. Is there any other way to accomplish this without using global variables, functions?

RBA
  • 12,337
  • 16
  • 79
  • 126
  • Kinda hard to see any benefit over a global variable holding the lock. – David Heffernan Jan 08 '19 at 11:02
  • I'm trying to avoid as much as possible using global variables. Of any kind... – RBA Jan 08 '19 at 11:04
  • Your class has two of them. – David Heffernan Jan 08 '19 at 11:12
  • Yes, linked to the class. Not defined as globalvar: FromWhereIsThisComming :) – RBA Jan 08 '19 at 11:13
  • 1
    But it's just different syntax for a global variable. Just sugar. If you don't like the initialization and finalization then you can replace them with class constructor and class destructor, which are called implicitly by initialization and finalization procedures. Is that what you are objecting to, the fact that there is code outside of the class? You want it to be self-contained? – David Heffernan Jan 08 '19 at 11:59
  • Also, FWIW, public constructor and destructor don't fit well with the singleton pattern. Of course, Delphi makes it hard to make class without a public constructor. – David Heffernan Jan 08 '19 at 12:00
  • Probably I'll use the class constructors and destructors, so everything should be in the same class. If you want to post it as an answer I'll accept it, otherwise I'll post my code. Thanks – RBA Jan 08 '19 at 12:43

1 Answers1

4

If you want to encapsulate all the necessary code inside the namespace of the class then you can replace the initialization and finalization sections with a class constructor and a class destructor, respectively. These will be called implicitly from the unit initialization and finalization procedures.

David Heffernan
  • 601,492
  • 42
  • 1,072
  • 1,490