My application used to be mono thread, but now to increase performance we need to make it multithread.
We have Lists and ListItems in the following architecture:
TBListItem = class(TBusinessObjects)
private
FList : TBList;
protected
//methods
public
constructor Create(AList: TBList); reintroduce;
//other methods
//properties...
end;
Instead of inheritance we prefer the composition of the list.
TBList = class(TPersistent)
private
FItemClass : TBListItemClass; //class of TBListItem
//this is used to AddObject(key, object) of the TStringList duplicates are no allowed
function BuildKey(ArrayOfKeys: array of Variant): string;
protected
//we use a stringlist to save the items
FList: TStringList;
function GetItem(Index: Integer): TBListItem;
//methods like Load(); Unload(); Save();
public
constructor Create(ARefClassItem: TBListItemClass); reintroduce;
//these methods use buildkey
function Add(ArrayOfKeys: Array of Variant): TBListItem; reintroduce;
function FindByKey(const ArrayOfKeys: array of Variant): TBListItem;
//other methods
//properties...
end;
In the ADD() method do this:
var Index: Integer;
begin
Index:= FList.IndexOf(BuildKey(ArrayOfKeys));
if Index <> -1 then
Result:= TBListItem(FList.Objects[Index])
else
begin
Result:= FListItemClass.Create(Self);
Result.FCodigo:= ArrayOfKeys;
//load data from database.
FList.AddObject(BuildKey(ArrayOfKeys), Result)
end;
end;
As i said, this objects are used to record cache data in runtime, but everytime we need to read/write objects in it, we have to:
EnterCriticalSection(instance of TRTLCriticalSection);
//Do Stuff
LeaveCriticalSection(Same instance);
I can't change much the architeture because there are inumerous classes that inherited from that.
When i run the processes, there are a lot of spikes in the processor graphic and a lot of downtimes too.
The system is compiled from delphi 6 compiler.
The Critical session has been created in the initialization of the unit.
Is there another way to do this ?
May I somehow at least not to lock the reading ?
Also, I have to guarantee the integrity, 2 object with the same key are not allowed.
You are going to need to perform some synchronisation on reading. You can't let one thread mutate a data structure whilst another tries to read it. A common approach is a single writer, multiple reader lock.
Delphi comes with one of these, namely TMultiReadExclusiveWriteSynchronizer
. However, I believe that its performance is poor, and since the TMonitor
debacle I personally have little faith in the ability of Emba's engineers to write correct synchronization primitives.
My recommendation would be to use the Slim Reader/Writer (SRW) Lock introduced in Vista. If you still need to support XP then I'd suggest falling back to a critical section.