Question

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.

Was it helpful?

Solution

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.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top