【问题标题】:How may i make global cache thread safe我怎样才能使全局缓存线程安全
【发布时间】:2013-02-20 13:25:20
【问题描述】:

我的应用程序曾经是单线程的,但现在为了提高性能,我们需要将其设为多线程。

我们在以下架构中有 Lists 和 ListItems:

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 个对象。

【问题讨论】:

  • Delphi 也有一个多读单写锁 - docwiki.embarcadero.com/Libraries/XE3/en/…,IIRC 它与 Delphi 6 一起出现。
  • 你怎么能不锁定阅读?如果在您阅读时出现写入怎么办?你能做的最好的就是单写/多读锁。或 RCU,但据我所知,这很棘手。
  • @Lloyd TMultiReadExclusiveWriteSynchonizer 有一个错误,我无法使用它。
  • @DavidHeffernan 你说的棘手是什么意思?
  • 这取决于这些变体的类型。如果它们只是一种类型,那么我将只使用该类型的数组(例如array of string)并使用VarAsTypeVarToStr 函数对它们进行类型转换,然后再将它们传递给您的公共方法。同样的方式你也可以修改你的私有方法。

标签: multithreading delphi thread-safety delphi-6 overhead-minimization


【解决方案1】:

您将需要在阅读时执行一些同步。你不能让一个线程改变一个数据结构,而另一个线程试图读取它。一种常见的方法是单个写入器,多个读取器锁。

Delphi 自带其中之一,即TMultiReadExclusiveWriteSynchronizer。但是,我认为它的性能很差,自从TMonitor 崩溃以来,我个人对 Emba 工程师编写正确同步原语的能力不太相信。

我的建议是使用 Vista 中引入的Slim Reader/Writer (SRW) Lock。如果您仍然需要支持 XP,那么我建议您退回到关键部分。

【讨论】:

猜你喜欢
  • 2012-04-15
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-10-02
  • 1970-01-01
  • 1970-01-01
  • 2012-05-22
  • 2011-03-27
相关资源
最近更新 更多