restemplate/indy/Core/IdThreadSafe.pas

897 lines
18 KiB
Plaintext

{
$Project$
$Workfile$
$Revision$
$DateUTC$
$Id$
This file is part of the Indy (Internet Direct) project, and is offered
under the dual-licensing agreement described on the Indy website.
(http://www.indyproject.org/)
Copyright:
(c) 1993-2005, Chad Z. Hower and the Indy Pit Crew. All rights reserved.
}
{
$Log$
}
{
Rev 1.10 2004.10.29 8:49:00 PM czhower
Fixed a constructor.
Rev 1.9 2004.10.27 9:20:04 AM czhower
For TIdStrings
Rev 1.8 10/26/2004 8:43:02 PM JPMugaas
Should be more portable with new references to TIdStrings and TIdStringList.
Rev 1.7 4/12/2004 4:50:36 PM JPMugaas
TIdThreadSafeInt64 created for some internal work but I figured it would help
with other stuff.
Rev 1.6 3/26/2004 1:09:28 PM JPMugaas
New ThreadSafe objects that I needed for some other work I'm doing.
Rev 1.5 3/17/2004 8:57:32 PM JPMugaas
Increment and decrement overloads added for quick math in the
TIdThreadSafeCardinal and TIdThreadSafeInteger. I need this for personal
work.
Rev 1.4 2004.02.25 8:23:20 AM czhower
Small changes
Rev 1.3 2004.02.03 4:17:00 PM czhower
For unit name changes.
Rev 1.2 2004.01.22 5:59:12 PM czhower
IdCriticalSection
Rev 1.1 3/27/2003 12:29:46 AM BGooijen
Added TIdThreadSafeList.Assign
Rev 1.0 11/13/2002 09:01:54 AM JPMugaas
}
unit IdThreadSafe;
interface
{$I IdCompilerDefines.inc}
//we need to put this in Delphi mode to work
uses
Classes,
{$IFDEF HAS_UNIT_Generics_Collections}
System.Generics.Collections,
{$ENDIF}
IdGlobal;
type
TIdThreadSafe = class
protected
FCriticalSection: TIdCriticalSection;
public
constructor Create; virtual;
destructor Destroy; override;
procedure Lock;
procedure Unlock;
end;
// Yes we know that integer operations are "atomic". However we do not like to rely on
// internal compiler implementation. This is a safe and proper way to keep our code independent
TIdThreadSafeInteger = class(TIdThreadSafe)
protected
FValue: Integer;
//
function GetValue: Integer;
procedure SetValue(const AValue: Integer);
public
function Decrement: Integer; overload;
function Decrement(const AValue : Integer) : Integer; overload;
function Increment: Integer; overload;
function Increment(const AValue : Integer) : Integer; overload;
//
property Value: Integer read GetValue write SetValue;
end;
TIdThreadSafeInt32 = TIdThreadSafeInteger;
TIdThreadSafeBoolean = class(TIdThreadSafe)
protected
FValue: Boolean;
//
function GetValue: Boolean;
procedure SetValue(const AValue: Boolean);
public
function Toggle: Boolean;
//
property Value: Boolean read GetValue write SetValue;
end;
TIdThreadSafeCardinal = class(TIdThreadSafe)
protected
FValue: Cardinal;
//
function GetValue: Cardinal;
procedure SetValue(const AValue: Cardinal);
public
function Decrement: Cardinal; overload;
function Decrement(const AValue : Cardinal) : Cardinal; overload;
function Increment: Cardinal; overload;
function Increment(const AValue : Cardinal) : Cardinal; overload;
//
property Value: Cardinal read GetValue write SetValue;
end;
TIdThreadSafeUInt32 = TIdThreadSafeCardinal;
TIdThreadSafeInt64 = class(TIdThreadSafe)
protected
FValue: Int64;
//
function GetValue: Int64;
procedure SetValue(const AValue: Int64);
public
function Decrement: Int64; overload;
function Decrement(const AValue : Int64) : Int64; overload;
function Increment: Int64; overload;
function Increment(const AValue : Int64) : Int64; overload;
//
property Value: Int64 read GetValue write SetValue;
end;
TIdThreadSafeString = class(TIdThreadSafe)
protected
FValue: string;
//
function GetValue: string;
procedure SetValue(const AValue: string);
public
procedure Append(const AValue: string);
procedure Prepend(const AValue: string);
//
property Value: string read GetValue write SetValue;
end;
TIdThreadSafeStringList = class(TIdThreadSafe)
protected
FValue: TStringList;
//
function GetValue(const AName: string): string;
procedure SetValue(const AName, AValue: string);
public
constructor Create; override;
destructor Destroy; override;
procedure Add(const AItem: string);
procedure AddObject(const AItem: string; AObject: TObject);
procedure Clear;
function Empty: Boolean;
function Lock: TStringList; reintroduce;
function ObjectByItem(const AItem: string): TObject;
procedure Remove(const AItem: string);
procedure Unlock; reintroduce;
property Values[const AName: string]: string read GetValue write SetValue;
end;
TIdThreadSafeDateTime = class(TIdThreadSafe)
protected
FValue : TDateTime;
function GetValue: TDateTime;
procedure SetValue(const AValue: TDateTime);
public
procedure Add(const AValue : TDateTime);
procedure Subtract(const AValue : TDateTime);
property Value: TDateTime read GetValue write SetValue;
end;
//In D7, a double is the same as a TDateTime. In DotNET, it is not.
TIdThreadSafeDouble = class(TIdThreadSafe)
protected
FValue : Double;
function GetValue: Double;
procedure SetValue(const AValue: Double);
public
procedure Add(const AValue : Double);
procedure Subtract(const AValue : Double);
property Value: Double read GetValue write SetValue;
end;
//TODO: Later make this descend from TIdThreadSafe instead
{$IFDEF HAS_GENERICS_TThreadList}
TIdThreadSafeList<T> = class(TThreadList<T>)
{$ELSE}
TIdThreadSafeList = class(TThreadList)
{$ENDIF}
public
procedure Assign(AThreadList: TThreadList{$IFDEF HAS_GENERICS_TThreadList}<T>{$ENDIF});overload;
procedure Assign(AList: TList{$IFDEF HAS_GENERICS_TList}<T>{$ENDIF});overload;
// Here to make it virtual
constructor Create; virtual;
function IsCountLessThan(const AValue: UInt32): Boolean;
function Count:Integer;
function IsEmpty: Boolean;
function Pop: {$IFDEF HAS_GENERICS_TThreadList}T{$ELSE}Pointer{$ENDIF};
function Pull: {$IFDEF HAS_GENERICS_TThreadList}T{$ELSE}Pointer{$ENDIF};
end;
{$IFDEF HAS_GENERICS_TObjectList}
TIdThreadSafeObjectList<T: class> = class(TIdThreadSafeList<T>)
{$ELSE}
TIdThreadSafeObjectList = class(TIdThreadSafeList)
{$ENDIF}
{$IFNDEF USE_OBJECT_ARC}
private
FOwnsObjects: Boolean;
{$ENDIF}
public
{$IFNDEF USE_OBJECT_ARC}
constructor Create; override;
destructor Destroy; override;
{$ENDIF}
procedure ClearAndFree;
{$IFNDEF USE_OBJECT_ARC}
property OwnsObjects: Boolean read FOwnsObjects write FOwnsObjects;
{$ENDIF}
end;
implementation
uses
{$IFDEF VCL_2010_OR_ABOVE}
{$IFDEF WINDOWS}
Windows,
{$ENDIF}
{$ENDIF}
{$IFDEF VCL_XE3_OR_ABOVE}
System.SyncObjs,
{$ENDIF}
SysUtils;
{ TIdThreadSafe }
constructor TIdThreadSafe.Create;
begin
inherited Create;
FCriticalSection := TIdCriticalSection.Create;
end;
destructor TIdThreadSafe.Destroy;
begin
FreeAndNil(FCriticalSection);
inherited Destroy;
end;
procedure TIdThreadSafe.Lock;
begin
FCriticalSection.Enter;
end;
procedure TIdThreadSafe.Unlock;
begin
FCriticalSection.Leave;
end;
{ TIdThreadSafeInteger }
function TIdThreadSafeInteger.Decrement: Integer;
begin
Lock;
try
Result := FValue;
Dec(FValue);
finally
Unlock;
end;
end;
function TIdThreadSafeInteger.Decrement(const AValue: Integer): Integer;
begin
Lock;
try
Result := FValue;
Dec(FValue,AValue);
finally
Unlock;
end;
end;
function TIdThreadSafeInteger.GetValue: Integer;
begin
Lock;
try
Result := FValue;
finally
Unlock;
end;
end;
function TIdThreadSafeInteger.Increment: Integer;
begin
Lock;
try
Result := FValue;
Inc(FValue);
finally
Unlock;
end;
end;
function TIdThreadSafeInteger.Increment(const AValue: Integer): Integer;
begin
Lock;
try
Result := FValue;
Inc(FValue,AValue);
finally
Unlock;
end;
end;
procedure TIdThreadSafeInteger.SetValue(const AValue: Integer);
begin
Lock;
try
FValue := AValue;
finally
Unlock;
end;
end;
{ TIdThreadSafeString }
procedure TIdThreadSafeString.Append(const AValue: string);
begin
Lock;
try
FValue := FValue + AValue;
finally
Unlock;
end;
end;
function TIdThreadSafeString.GetValue: string;
begin
Lock;
try
Result := FValue;
finally
Unlock;
end;
end;
procedure TIdThreadSafeString.Prepend(const AValue: string);
begin
Lock;
try
FValue := AValue + FValue;
finally
Unlock;
end;
end;
procedure TIdThreadSafeString.SetValue(const AValue: string);
begin
Lock;
try
FValue := AValue;
finally
Unlock;
end;
end;
{ TIdThreadSafeStringList }
procedure TIdThreadSafeStringList.Add(const AItem: string);
begin
Lock;
try
FValue.Add(AItem);
finally
Unlock;
end;
end;
procedure TIdThreadSafeStringList.AddObject(const AItem: string; AObject: TObject);
begin
Lock;
try
FValue.AddObject(AItem, AObject);
finally
Unlock;
end;
end;
procedure TIdThreadSafeStringList.Clear;
begin
Lock;
try
FValue.Clear;
finally
Unlock;
end;
end;
constructor TIdThreadSafeStringList.Create;
begin
inherited Create;
FValue := TStringList.Create;
end;
destructor TIdThreadSafeStringList.Destroy;
begin
inherited Lock;
try
FreeAndNil(FValue);
finally
inherited Unlock;
end;
inherited Destroy;
end;
function TIdThreadSafeStringList.Empty: Boolean;
begin
Lock;
try
Result := FValue.Count = 0;
finally Unlock; end;
end;
function TIdThreadSafeStringList.GetValue(const AName: string): string;
begin
Lock;
try
Result := FValue.Values[AName];
finally
Unlock;
end;
end;
function TIdThreadSafeStringList.Lock: TStringList;
begin
inherited Lock;
Result := FValue;
end;
function TIdThreadSafeStringList.ObjectByItem(const AItem: string): TObject;
var
i: Integer;
begin
Result := nil;
Lock;
try
i := FValue.IndexOf(AItem);
if i > -1 then begin
Result := FValue.Objects[i];
end;
finally
Unlock;
end;
end;
procedure TIdThreadSafeStringList.Remove(const AItem: string);
var
i: Integer;
begin
Lock;
try
i := FValue.IndexOf(AItem);
if i > -1 then begin
FValue.Delete(i);
end;
finally
Unlock;
end;
end;
procedure TIdThreadSafeStringList.SetValue(const AName, AValue: string);
begin
Lock;
try
FValue.Values[AName] := AValue;
finally
Unlock;
end;
end;
procedure TIdThreadSafeStringList.Unlock;
begin
inherited Unlock;
end;
{ TIdThreadSafeCardinal }
function TIdThreadSafeCardinal.Decrement: Cardinal;
begin
Lock;
try
Result := FValue;
Dec(FValue);
finally
Unlock;
end;
end;
function TIdThreadSafeCardinal.Decrement(const AValue: Cardinal): Cardinal;
begin
Lock;
try
Result := FValue;
Dec(FValue,AValue);
finally
Unlock;
end;
end;
function TIdThreadSafeCardinal.GetValue: Cardinal;
begin
Lock;
try
Result := FValue;
finally
Unlock;
end;
end;
function TIdThreadSafeCardinal.Increment: Cardinal;
begin
Lock;
try
Result := FValue;
Inc(FValue);
finally
Unlock;
end;
end;
function TIdThreadSafeCardinal.Increment(const AValue: Cardinal): Cardinal;
begin
Lock;
try
Result := FValue;
Inc(FValue,AValue);
finally
Unlock;
end;
end;
procedure TIdThreadSafeCardinal.SetValue(const AValue: Cardinal);
begin
Lock;
try
FValue := AValue;
finally
Unlock;
end;
end;
{ TIdThreadSafeList }
function TIdThreadSafeList{$IFDEF HAS_GENERICS_TThreadList}<T>{$ENDIF}.IsCountLessThan(const AValue: UInt32): Boolean;
begin
if Assigned(Self) then begin
Result := UInt32(Count) < AValue;
end else begin
Result := True; // none always <
end;
end;
function TIdThreadSafeList{$IFDEF HAS_GENERICS_TThreadList}<T>{$ENDIF}.IsEmpty: Boolean;
begin
Result := IsCountLessThan(1);
end;
{$IFDEF HAS_GENERICS_TThreadList}
function TIdThreadSafeList<T>.Pop: T;
{$ELSE}
function TIdThreadSafeList.Pop: Pointer;
{$ENDIF}
var
LList: TList{$IFDEF HAS_GENERICS_TList}<T>{$ENDIF};
begin
LList := LockList;
try
if LList.Count > 0 then begin
Result := LList.Items[Count - 1];
LList.Delete(Count - 1);
end else begin
Result := {$IFDEF HAS_GENERICS_TThreadList}Default(T){$ELSE}nil{$ENDIF};
end;
finally
UnlockList;
end;
end;
{$IFDEF HAS_GENERICS_TThreadList}
function TIdThreadSafeList<T>.Pull: T;
{$ELSE}
function TIdThreadSafeList.Pull: Pointer;
{$ENDIF}
var
LList: TList{$IFDEF HAS_GENERICS_TList}<T>{$ENDIF};
begin
LList := LockList;
try
if LList.Count > 0 then begin
Result := LList.Items[0];
LList.Delete(0);
end else begin
Result := {$IFDEF HAS_GENERICS_TThreadList}Default(T){$ELSE}nil{$ENDIF};
end;
finally
UnlockList;
end;
end;
{$IFDEF HAS_GENERICS_TThreadList}
procedure TIdThreadSafeList<T>.Assign(AList: TList<T>);
{$ELSE}
procedure TIdThreadSafeList.Assign(AList: TList);
{$ENDIF}
var
i: integer;
LList: TList{$IFDEF HAS_GENERICS_TList}<T>{$ENDIF};
begin
LList := LockList;
try
LList.Clear;
LList.Capacity := AList.Capacity;
for i := 0 to AList.Count - 1 do begin
LList.Add(AList.Items[i]);
end;
finally
UnlockList;
end;
end;
{$IFDEF HAS_GENERICS_TThreadList}
procedure TIdThreadSafeList<T>.Assign(AThreadList: TThreadList<T>);
{$ELSE}
procedure TIdThreadSafeList.Assign(AThreadList: TThreadList);
{$ENDIF}
var
LList: TList{$IFDEF HAS_GENERICS_TList}<T>{$ENDIF};
begin
LList := AThreadList.LockList;
try
Assign(LList);
finally
AThreadList.UnlockList;
end;
end;
constructor TIdThreadSafeList{$IFDEF HAS_GENERICS_TThreadList}<T>{$ENDIF}.Create;
begin
inherited Create;
end;
function TIdThreadSafeList{$IFDEF HAS_GENERICS_TThreadList}<T>{$ENDIF}.Count: Integer;
var
LList: TList{$IFDEF HAS_GENERICS_TList}<T>{$ENDIF};
begin
LList := LockList;
try
Result := LList.Count;
finally
UnlockList;
end;
end;
{ TIdThreadSafeObjectList }
{$IFNDEF USE_OBJECT_ARC}
constructor TIdThreadSafeObjectList{$IFDEF HAS_GENERICS_TObjectList}<T>{$ENDIF}.Create;
begin
inherited Create;
OwnsObjects := False;
end;
destructor TIdThreadSafeObjectList{$IFDEF HAS_GENERICS_TObjectList}<T>{$ENDIF}.Destroy;
begin
if OwnsObjects then ClearAndFree;
inherited;
end;
{$ENDIF}
procedure TIdThreadSafeObjectList{$IFDEF HAS_GENERICS_TObjectList}<T>{$ENDIF}.ClearAndFree;
var
LList: TList{$IFDEF HAS_GENERICS_TList}<T>{$ENDIF};
i: Integer;
begin
LList := LockList;
try
{$IFNDEF USE_OBJECT_ARC}
for i := 0 to LList.Count-1 do begin
{$IFDEF HAS_GENERICS_TList}LList[i]{$ELSE}TObject(LList[i]){$ENDIF}.Free;
end;
{$ENDIF}
LList.Clear;
finally
UnlockList;
end;
end;
{ TIdThreadSafeBoolean }
function TIdThreadSafeBoolean.GetValue: Boolean;
begin
Lock;
try
Result := FValue;
finally
Unlock;
end;
end;
procedure TIdThreadSafeBoolean.SetValue(const AValue: Boolean);
begin
Lock;
try
FValue := AValue;
finally
Unlock;
end;
end;
function TIdThreadSafeBoolean.Toggle: Boolean;
begin
Lock;
try
FValue := not FValue;
Result := FValue;
finally
Unlock;
end;
end;
{ TIdThreadSafeDateTime }
procedure TIdThreadSafeDateTime.Add(const AValue: TDateTime);
begin
Lock;
try
FValue := FValue + AValue;
finally
Unlock;
end;
end;
function TIdThreadSafeDateTime.GetValue: TDateTime;
begin
Lock;
try
Result := FValue;
finally
Unlock;
end;
end;
procedure TIdThreadSafeDateTime.SetValue(const AValue: TDateTime);
begin
Lock;
try
FValue := AValue;
finally
Unlock;
end;
end;
procedure TIdThreadSafeDateTime.Subtract(const AValue: TDateTime);
begin
Lock;
try
FValue := FValue - AValue;
finally
Unlock;
end;
end;
{ TIdThreadSafeDouble }
procedure TIdThreadSafeDouble.Add(const AValue: Double);
begin
Lock;
try
FValue := FValue + AValue;
finally
Unlock;
end;
end;
function TIdThreadSafeDouble.GetValue: Double;
begin
Lock;
try
Result := FValue;
finally
Unlock;
end;
end;
procedure TIdThreadSafeDouble.SetValue(const AValue: Double);
begin
Lock;
try
FValue := AValue;
finally
Unlock;
end;
end;
procedure TIdThreadSafeDouble.Subtract(const AValue: Double);
begin
Lock;
try
FValue := FValue - AValue;
finally
Unlock;
end;
end;
{ TIdThreadSafeInt64 }
function TIdThreadSafeInt64.Decrement(const AValue: Int64): Int64;
begin
Lock;
try
Result := FValue;
Dec(FValue,AValue);
finally
Unlock;
end;
end;
function TIdThreadSafeInt64.Decrement: Int64;
begin
Lock;
try
Result := FValue;
Dec(FValue);
finally
Unlock;
end;
end;
function TIdThreadSafeInt64.GetValue: Int64;
begin
Lock;
try
Result := FValue;
finally
Unlock;
end;
end;
function TIdThreadSafeInt64.Increment(const AValue: Int64): Int64;
begin
Lock;
try
Result := FValue;
Inc(FValue,AValue);
finally
Unlock;
end;
end;
function TIdThreadSafeInt64.Increment: Int64;
begin
Lock;
try
Result := FValue;
Inc(FValue);
finally
Unlock;
end;
end;
procedure TIdThreadSafeInt64.SetValue(const AValue: Int64);
begin
Lock;
try
FValue := AValue;
finally
Unlock;
end;
end;
end.