讨论下lazy-loading和线程安全
大家一定听说过lazy-loading(延迟加载),简单来说,延迟加载就是只有当需要某资源的时候才去加载,以减少不必要的系统开销。如下面的代码所示,仅在访问Members属性的时候创建列表(而不是在constructor内创建)
type TPerson = class end; TMembers = TObjectList<TPerson>; TGroup = class private fMembers: TMembers; function GetMembers: TMembers; public destructor Destroy; override; //... property Members: TMembers read GetMembers; end;//...destructor TGroup.Destroy;begin fMembers.Free; inherited Destroy;end;function TGroup.GetMembers: TMembers;begin if fMembers = nil then begin fMembers := TMembers.Create; end; Result := fMembers;end;
// fCriticalSection: SyncObjs.TCriticalSection;constructor TGroup.Create;begin inherited Create; fCriticalSection := TCriticalSection.Create;end;destructor TGroup.Destroy;begin fMembers.Free; fCriticalSection.Free; inherited Destroy;end;function TGroup.GetMembers: TMembers;begin fCriticalSection.Enter; try if fMembers = nil then begin fMembers := TMembers.Create; end; Result := fMembers; finally fCriticalSection.Leave; end;end;
function TGroup.GetMembers: TMembers;begin if fMembers = nil then // 先判断fMembers是否为nil,若为nil才进入临界区 begin fCriticalSection.Enter; try if fMembers = nil then // 再次判断fMembers(这就是double-checked locking的由来) begin fMembers := TMembers.Create; end; finally fCriticalSection.Leave; end; end; Result := fMembers;end;
function TGroup.GetMembers: TMembers;begin if fMembers = nil then begin fCriticalSection.Enter; try MemoryBarrier; if fMembers = nil then begin fMembers := TMembers.Create; end; finally fCriticalSection.Leave; end; end; Result := fMembers;end;
function TGroup.GetMembers: TMembers;var list: TMembers;begin if fMembers = nil then begin list := TMembers.Create; if InterlockedCompareExchangePointer(fMembers, list, nil) <> nil then begin list.Free; end; end; Result := fMembers;end;
// fMembersSync: SysUtils.IReadWriteSync;constructor TGroup.Create;begin inherited Create; fMembersSync := TMREWSync.Create; // or TMultiReadExclusiveWriteSynchronizer.Create;end;destructor TGroup.Destroy;begin fMembers.Free; inherited Destroy;end;function TGroup.FindMember(const name: string): TPerson;var person: TPerson;begin fMembersSync.BeginRead; // 查找成员是“读操作” try for person in Members do begin if SameText(person.Name, name) then begin Result := person; Break; end; end; finally fMembersSync.EndRead; end;end;procedure TGroup.AddMember(person: TPerson);begin fMembersSync.BeginWrite; // 添加成员属于“写操作” try Members.Add(person); finally fMembersSync.EndWrite; end;end;// 这里用读写锁应该没有意义,是不是要用上面的某种方法来保证线程安全???function TGroup.GetMembers: TMembers;begin end;