我有简单的线程安全容器类。它具有标准的添加/删除方法。通常枚举项目被实现为:
MyList.lock;
try
// looping here
finally
MyList.unlock;
end;
但我想以线程安全的方式利用 for-in 支持:
for item in MyList do
begin
// do something
end;
我的枚举器实现将容器锁定在它的构造函数中,并在析构函数中解锁它。这是可行的,但前提是 Enumerator 的实例是在 for-in 循环的开头创建并在最后被销毁的。我在这里找到了解释:Enumerator created with for in construction 是如何被破坏的?
但是由于锁定/解锁是一项关键操作,我想知道这种用法是否可以?
这是我的实现:
TContainer<T> = class
private
FPadLock: TObject;
FItems: TList<T>;
protected
public
type
TContainerEnumerator = class(TList<T>.TEnumerator)
private
FContainer: TContainer<T>;
public
constructor Create(AContainer: TContainer<T>);
destructor Destroy; override;
end;
constructor Create;
destructor Destroy; override;
procedure add(AItem: T);
procedure remove(AItem: T);
function GetEnumerator: TContainerEnumerator;
end;
{ TContainer<T> }
procedure TContainer<T>.add(AItem: T);
begin
TMonitor.Enter(FPadLock);
try
FItems.Add(AItem);
finally
TMonitor.Exit(FPadLock);
end;
end;
constructor TContainer<T>.Create;
begin
inherited Create;
FPadLock := TObject.Create;
FItems := TList<T>.Create;
end;
destructor TContainer<T>.Destroy;
begin
FreeAndNil(FItems);
FreeAndNil(FPadLock);
inherited;
end;
procedure TContainer<T>.remove(AItem: T);
begin
TMonitor.Enter(FPadLock);
try
FItems.Remove(AItem);
finally
TMonitor.Exit(FPadLock);
end;
end;
function TContainer<T>.GetEnumerator: TContainerEnumerator;
begin
result := TContainerEnumerator.Create(self);
end;
{ TContainer<T>.TContainerEnumerator }
constructor TContainer<T>.TContainerEnumerator.Create(
AContainer: TContainer<T>);
begin
inherited Create(AContainer.FItems);
FContainer := AContainer;
TMonitor.Enter(FContainer.FPadLock); // <<< Lock parent container using Monitor
end;
destructor TContainer<T>.TContainerEnumerator.Destroy;
begin
TMonitor.Exit(FContainer.FPadLock); // <<< Unlock parent container
inherited;
end;