Как я могу сделать глобальный поток кеша безопасным

Раньше мое приложение было монопоточным, но теперь для повышения производительности нам нужно сделать его многопоточным.

У нас есть списки и элементы списка в следующей архитектуре:

TBListItem = class(TBusinessObjects)
private 
  FList : TBList;
protected
  //methods
public 
  constructor Create(AList: TBList); reintroduce;
  //other methods
  //properties... 
end;

Вместо наследования мы предпочитаем состав списка.

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;

В методе ADD() сделайте это:

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;

Как я уже сказал, эти объекты используются для записи данных кэша во время выполнения, но каждый раз, когда нам нужно для чтения / записи объектов в нем, мы должны:

EnterCriticalSection(instance of TRTLCriticalSection);
//Do Stuff
LeaveCriticalSection(Same instance);

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

Есть ли другой способ сделать это?
Можно ли как-нибудь хотя бы не заблокировать чтение?

Также я должен гарантировать целостность, 2 объекта с одинаковым ключом не допускаются.

1 ответ

Решение

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

Delphi поставляется с одним из них, а именно TMultiReadExclusiveWriteSynchronizer, Тем не менее, я считаю, что его производительность оставляет желать лучшего, и поскольку TMonitor Я лично мало верю в способность инженеров Emba писать правильные примитивы синхронизации.

Я рекомендую использовать Slim Reader/Writer (SRW) Lock, представленный в Vista. Если вам все еще нужна поддержка XP, я бы предложил вернуться к критическому разделу.

Другие вопросы по тегам