2011. március 28., hétfő

Create a thread-safe wrapper class for TCustomIniFile descendents


Problem/Question/Abstract:

How to create a thread-safe wrapper class for TCustomIniFile descendents

Answer:

{Unit ThreadSafeWrapperU:
Declares and implements a simple thread-safe wrapper class as base class
for classes that need to serialize access to some internal object.

Author Dr. Peter Below
Version 1.0 created 18 Oktober 2000
Current revision: 1.0
Last modified: 18 Oktober 2000
Last review: 18.04.2001}

unit ThreadSafeWrapperU;

interface

uses SyncObjs;

type

  {This is a class from which classes wrapping some data object in a thread-safe
manner can be derived. The derived class should add a public
Function Lock: Sometype;
that calls InternalLock and then returns a reference for the protected object (kept in a private field ).
  Access to the protected object will typically take the form

     with wrapper.lock do
     try
       stuff
     finally
       wrapper.Unlock;
     end;}

  TThreadSafeWrapper = class
  private
    FGuardian: TCriticalSection;
  protected
    {Enter the critical section}
    procedure InternalLock;
  public
    {Create the critical section}
    constructor Create; virtual;
    {Destroy the critical section}
    destructor Destroy; override;
    {Leave the critical section}
    procedure Unlock;
  end;

implementation

constructor TThreadSafeWrapper.Create;
begin
  FGuardian := TCriticalSection.Create;
  inherited;
end;

destructor TThreadSafeWrapper.Destroy;
begin
  FGuardian.Free;
  inherited;
end;

procedure TThreadSafeWrapper.InternalLock;
begin
  FGuardian.Acquire;
end;

procedure TThreadSafeWrapper.Unlock;
begin
  FGuardian.Release;
end;

end.

{ThreadSafeInifileU:
Implements a thread-safe wrapper class for TCustomInifile descendents.

Author Dr. Peter Below
Version 1.0 created 24.12.2000
Version 1.01 created 25.04.2001, added most of the public inifile methods to wrap
              access to the internal inifile
Current revision: 1.01
Last modified: 24.12.2000
Last review: 25.04.2001}

unit ThreadSafeInifileU;

interface

uses
  Windows, Classes, ThreadSafeWrapperU, Inifiles;

type
  {Enumerated type for TCustomInifile descendents to use}
  TIniType = (itRegistryInifile, itInifile, itMemInifile);

  {A thread-safe inifile class. The default inifile class used if none is specified in
  the constructor is TRegistryInifile}
  TThreadsafeInifile = class(TThreadSafeWrapper)
  private
    FIni: TCustomInifile;
  public
    constructor Create(aFilename: string; aClass: TIniType = itRegistryInifile;
      aAccess: LongWord = KEY_READ or KEY_WRITE); reintroduce;
    destructor Destroy; override;
    function Lock: TCustomInifile;
    function SectionExists(const Section: string): Boolean;
    function ReadString(const Section, Ident, Default: string): string;
    procedure WriteString(const Section, Ident, Value: string);
    function ReadInteger(const Section, Ident: string; Default: Longint): Longint;
    procedure WriteInteger(const Section, Ident: string; Value: Longint);
    function ReadBool(const Section, Ident: string; Default: Boolean): Boolean;
    procedure WriteBool(const Section, Ident: string; Value: Boolean);
    function ReadDate(const Section, Ident: string; Default: TDateTime): TDateTime;
    function ReadDateTime(const Section, Ident: string; Default: TDateTime):
      TDateTime;
    function ReadFloat(const Section, Ident: string; Default: Double): Double;
    function ReadTime(const Section, Ident: string; Default: TDateTime): TDateTime;
    procedure WriteDate(const Section, Ident: string; Value: TDateTime);
    procedure WriteDateTime(const Section, Ident: string; Value: TDateTime);
    procedure WriteFloat(const Section, Ident: string; Value: Double);
    procedure WriteTime(const Section, Ident: string; Value: TDateTime);
    procedure ReadSection(const Section: string; Strings: TStrings);
    procedure ReadSections(Strings: TStrings);
    procedure ReadSectionValues(const Section: string; Strings: TStrings);
    procedure EraseSection(const Section: string);
    procedure DeleteKey(const Section, Ident: string);
    function ValueExists(const Section, Ident: string): Boolean;
  end;

implementation

uses
  Registry;

{TThreadsafeInifile.Create:
Create the custom ini file descendent.

Parameters:
aFilename: The name to use.
aClass: Defines the class to use.
aAccess: The desired access if aclass is itRegistryInifile.

We have a slight problem here since TCustomInifile.Create is not a virtual constructor.
So we need a somewhat cumbersome Case construct to create the correct class of
TCustomInifile descendent.

Created 24.12.2000 by P. Below}

constructor TThreadsafeInifile.Create(aFilename: string; aClass: TIniType =
  itRegistryInifile;
  aAccess: DWord = KEY_READ or KEY_WRITE);
begin
  inherited Create;
  case aClass of
    itRegistryInifile:
      FIni := TRegistryInifile.Create(aFilename, aAccess);
    itInifile:
      FIni := TInifile.Create(aFilename);
    itMemInifile:
      FIni := TMemInifile.Create(aFilename);
  end;
end;

{TThreadsafeInifile.Destroy:
Destroy the internal inifile object.

Created 24.12.2000 by P. Below}

destructor TThreadsafeInifile.Destroy;
begin
  FIni.Free;
  inherited;
end;

{TThreadsafeInifile.Lock:
Aquire access to the ini file and return its reference. Must be paired with an Unlock call!

Created 24.12.2000 by P. Below}

function TThreadsafeInifile.Lock: TCustomInifile;
begin
  InternalLock;
  Result := FIni;
end;

function TThreadsafeInifile.SectionExists(const Section: string): Boolean;
begin
  InternalLock;
  try
    Result := FIni.SectionExists(Section);
  finally
    Unlock;
  end;
end;

function TThreadsafeInifile.ReadString(const Section, Ident, Default: string): string;
begin
  InternalLock;
  try
    Result := FIni.ReadString(Section, Ident, Default);
  finally
    Unlock;
  end;
end;

procedure TThreadsafeInifile.WriteString(const Section, Ident, Value: string);
begin
  InternalLock;
  try
    FIni.WriteString(Section, Ident, Value);
  finally
    Unlock;
  end;
end;

function TThreadsafeInifile.ReadInteger(const Section, Ident: string; Default:
  Longint): Longint;
begin
  InternalLock;
  try
    Result := FIni.ReadInteger(Section, Ident, Default);
  finally
    Unlock;
  end;
end;

procedure TThreadsafeInifile.WriteInteger(const Section, Ident: string; Value:
  Longint);
begin
  InternalLock;
  try
    FIni.WriteInteger(Section, Ident, Value);
  finally
    Unlock;
  end;
end;

function TThreadsafeInifile.ReadBool(const Section, Ident: string; Default: Boolean):
  Boolean;
begin
  InternalLock;
  try
    Result := FIni.ReadBool(Section, Ident, Default);
  finally
    Unlock;
  end;
end;

procedure TThreadsafeInifile.WriteBool(const Section, Ident: string; Value: Boolean);
begin
  InternalLock;
  try
    FIni.WriteBool(Section, Ident, Value);
  finally
    Unlock;
  end;
end;

function TThreadsafeInifile.ReadDate(const Section, Ident: string; Default:
  TDateTime): TDateTime;
begin
  InternalLock;
  try
    Result := FIni.ReadDate(Section, Ident, Default);
  finally
    Unlock;
  end;
end;

function TThreadsafeInifile.ReadDateTime(const Section, Ident: string;
  Default: TDateTime): TDateTime;
begin
  InternalLock;
  try
    Result := FIni.ReadDatetime(Section, Ident, Default);
  finally
    Unlock;
  end;
end;

function TThreadsafeInifile.ReadFloat(const Section, Ident: string; Default: Double):
  Double;
begin
  InternalLock;
  try
    Result := FIni.ReadFloat(Section, Ident, Default);
  finally
    Unlock;
  end;
end;

function TThreadsafeInifile.ReadTime(const Section, Ident: string; Default:
  TDateTime): TDateTime;
begin
  InternalLock;
  try
    Result := FIni.ReadTime(Section, Ident, Default);
  finally
    Unlock;
  end;
end;

procedure TThreadsafeInifile.WriteDate(const Section, Ident: string; Value:
  TDateTime);
begin
  InternalLock;
  try
    FIni.WriteDate(Section, Ident, Value);
  finally
    Unlock;
  end;
end;

procedure TThreadsafeInifile.WriteDateTime(const Section, Ident: string; Value:
  TDateTime);
begin
  InternalLock;
  try
    FIni.WriteDatetime(Section, Ident, Value);
  finally
    Unlock;
  end;
end;

procedure TThreadsafeInifile.WriteFloat(const Section, Ident: string; Value: Double);
begin
  InternalLock;
  try
    FIni.WriteFloat(Section, Ident, Value);
  finally
    Unlock;
  end;
end;

procedure TThreadsafeInifile.WriteTime(const Section, Ident: string; Value:
  TDateTime);
begin
  InternalLock;
  try
    FIni.WriteTime(Section, Ident, Value);
  finally
    Unlock;
  end;
end;

procedure TThreadsafeInifile.ReadSection(const Section: string; Strings: TStrings);
begin
  InternalLock;
  try
    FIni.ReadSection(Section, Strings);
  finally
    Unlock;
  end;
end;

procedure TThreadsafeInifile.ReadSections(Strings: TStrings);
begin
  InternalLock;
  try
    FIni.ReadSections(Strings);
  finally
    Unlock;
  end;
end;

procedure TThreadsafeInifile.ReadSectionValues(const Section: string; Strings:
  TStrings);
begin
  InternalLock;
  try
    FIni.ReadSectionValues(Section, Strings);
  finally
    Unlock;
  end;
end;

procedure TThreadsafeInifile.EraseSection(const Section: string);
begin
  InternalLock;
  try
    FIni.EraseSection(Section);
  finally
    Unlock;
  end;
end;

procedure TThreadsafeInifile.DeleteKey(const Section, Ident: string);
begin
  InternalLock;
  try
    FIni.DeleteKey(Section, Ident);
  finally
    Unlock;
  end;
end;

function TThreadsafeInifile.ValueExists(const Section, Ident: string): Boolean;
begin
  InternalLock;
  try
    Result := FIni.ValueExists(Section, Ident);
  finally
    Unlock;
  end;
end;

end.

Nincsenek megjegyzések:

Megjegyzés küldése