Карта сайта Kansoftware
НОВОСТИУСЛУГИРЕШЕНИЯКОНТАКТЫ
KANSoftWare

Использование синглтона для блокировки критической секции в объектно-ориентированном Delphi

Delphi , Компоненты и Классы , Потоки

Использование синглтона для блокировки критической секции в объектно-ориентированном Delphi

Вопрос разработчика связан с реализацией синглтона для критической секции в Delphi, что позволяет защищать код в многоклассовых системах. Существуют различные подходы к созданию синглтона, но разработчик выразил нежелание использовать глобальные функции для возврата экземпляра синглтона. В результате был реализован собственный вариант синглтона с двойной проверкой блокировки.

Проблема

Разработчик стремится использовать синглтон для критической секции в нескольких классах, чтобы обеспечить безопасность выполнения кода в многопоточной среде. Он не хочет использовать глобальные функции для доступа к экземпляру синглтона, как это реализовано в некоторых стандартных паттернах.

Решение

Разработчик предложил свой вариант реализации синглтона, который использует двойную проверку блокировки для гарантии того, что экземпляр синглтона будет создан только один раз. Код синглтона содержит критическую секцию, которая управляется локально, а не глобально.

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;
{Double check locking for this singleton}
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.

Альтернативный ответ

Разработчик выразил недовольство по поводу использования глобальных переменных и функций для инициализации и финализации синглтона, и предложил альтернативу с использованием конструктора и деструктора класса. Это позволяет избежать явного использования глобальных переменных и делает код более самодостаточным.

Подтвержденный ответ

Использование конструктора класса и деструктора класса позволяет заменить глобальные инициализацию и финализацию, что делает реализацию более чистой и избегает использования внешних глобальных переменных. Вместо этого все необходимое для работы синглтона заключено внутри самого класса.

type
  TSynchronizationHandler = class
  private
    FCriticalSection: TCriticalSection;
    class var FSingletonInstance: TSyncHelper;
    class function InstanceClass: TSyncHelper; static;
  protected
    constructor Create;
    destructor Destroy; override;
  public
    class procedure Initialize;
    class procedure Finalize;
    procedure Lock;
    procedure Unlock;
  end;

{ Конструктор класса, выполняется при создании экземпляра класса }
constructor TSynchronizationHandler.Create;
begin
  FCriticalSection := TCriticalSection.Create;
end;

{ Деструктор класса, вызывается при освобождении экземпляра класса }
destructor TSynchronizationHandler.Destroy;
begin
  FCriticalSection.Free;
  inherited Destroy;
end;

{ Статический класс конструктор }
class procedure TSynchronizationHandler.Initialize;
begin
  with TSynchronizationHandler do
  begin
    FSingletonInstance := nil;
    FSingletonInstance := TSynchronizationHandler.InstanceClass;
    FSingletonInstance.FCriticalSection := TCriticalSection.Create;
  end;
end;

{ Статический класс деструктор }
class procedure TSynchronizationHandler.Finalize;
begin
  with TSynchronizationHandler do
  begin
    FSingletonInstance.FCriticalSection.Free;
    FSingletonInstance.Free;
  end;
end;

{ Статический метод для доступа к экземпляру синглтона }
class function TSynchronizationHandler.InstanceClass: TSynchronizationHandler;
begin
  if FSingletonInstance is nil then
  begin
    FSingletonInstance := TSynchronizationHandler.Create;
    FSingletonInstance.FCriticalSection.Acquire;
    try
      if FSingletonInstance is nil then
      begin
        FSingletonInstance := TSynchronizationHandler.Create;
        FSingletonInstance.FCriticalSection := TCriticalSection.CreateSharedOwner;
      end;
    finally
      FSingletonInstance.FCriticalSection.Release;
    end;
  end;
  Result := FSingletonInstance;
end;

{ Вход в критическую секцию }
procedure TSynchronizationHandler.Lock;
begin
  if Assigned(FSingletonInstance) then
    FSingletonInstance.FCriticalSection.Acquire;
end;

{ Выход из критической секции }
procedure TSynchronizationHandler.Unlock;
begin
  if Assigned(FSingletonInstance) then
    FSingletonInstance.FCriticalSection.Release;
end;

{ Статический класс конструктор вызывается при подключении модуля }
initialization
  TSynchronizationHandler.Initialize;
finalization
  TSynchronizationHandler.Finalize;

Вызов конструктора и деструктора класса

При использовании конструкторов и деструкторов класса, они вызываются автоматически. Конструктор класса вызывается при первом обращении к экземпляру класса (например, через статический метод InstanceClass), что гарантирует, что экземпляр синглтона будет создан до первого обращения к его экземпляру. Деструктор вызывается в конце работы программы, что освобождает связанные с классом ресурсы, если это необходимо.

Заключение

Использование конструкторов и деструкторов класса в Delphi позволяет избежать использования глобальных переменных и функций для инициализации и финализации объекта, не теряя при этом свойства синглтона, таких как единственность экземпляра и обходность множественного инициализирования, что важно в многопоточных приложениях. Это также позволяет сохранить чистоту и самодокументированность кода, сохраняя его полностью внутри класса, что удобно для модульного тестирования и развертывания системы контроля версий.

Создано по материалам из источника по ссылке.

Описание контекста: Разработчик в Delphi реализует синглтон для управления критической секцией в многоклассовых системах, избегая глобальных функций для доступа к экземпляру синглтона.


Комментарии и вопросы

Получайте свежие новости и обновления по Object Pascal, Delphi и Lazarus прямо в свой смартфон. Подпишитесь на наш Telegram-канал delphi_kansoftware и будьте в курсе последних тенденций в разработке под Linux, Windows, Android и iOS




Материалы статей собраны из открытых источников, владелец сайта не претендует на авторство. Там где авторство установить не удалось, материал подаётся без имени автора. В случае если Вы считаете, что Ваши права нарушены, пожалуйста, свяжитесь с владельцем сайта.


:: Главная :: Потоки ::


реклама


©KANSoftWare (разработка программного обеспечения, создание программ, создание интерактивных сайтов), 2007
Top.Mail.Ru

Время компиляции файла: 2024-12-22 20:14:06
2024-12-26 14:08:30/0.0035710334777832/0