作者热门文章
- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我很难理解为什么 XPObserver.pas 中的 TXPSubject.DeleteObserver 和 TXPSubject.DeleteObservers 的实现不同的原因?具体来说,“Dispose”和“ReleaseSubject”调用的不同顺序,以及不同顺序对 TXPSubject.DeleteObserver 很重要的原因。有问题的代码被提取并显示在下面。该文件可从 DUnit 获得。
function TXPSubject.DeleteObserver(const Observer: IXPObserver;
const Context: pointer): boolean;
var
idx: integer;
ObserverInfo: TXPObserverInfo;
begin
FSync.Enter;
try
// Check for existence or prior removal
Result := FindObserver(Observer, Context, idx);
if Result then
begin
// Need local ref after deletion from list. Order of Delete() &
// ReleaseSubject() is important here for correct functioning of _Release
// ...***DON'T*** refactor this method!!
ObserverInfo := PXPObserverInfo(FObservers[idx])^;
// Release our (list) reference to observer
PXPObserverInfo(FObservers[idx])^.Observer := nil;
System.Dispose(FObservers[idx]);
FObservers.Delete(idx);
end;
// Exit critical section here as we now have local vars only (thread-safe)
// and call to ReleaseSubject below on last reference will leave FSync
// invalid (destroyed).
finally
FSync.Leave;
end;
// Notify Observer to release reference to us. This will result in
// a call to TXPSubject._Release.
if Result then
ObserverInfo.Observer.ReleaseSubject(IXPSubject(ObserverInfo.Subject),
ObserverInfo.Context);
end;
procedure TXPSubject.DeleteObservers;
var
idx: integer;
ObserverInfo: PXPObserverInfo;
begin
FDeletingObservers := true;
// Count *down* to allow for side-effect of loop actions -
// referenced item will be deleted from list, and remainder will move down
// one slot.
for idx := FObservers.Count - 1 downto 0 do
begin
ObserverInfo := FObservers[idx];
// Notify Observer to release reference to Subject
ObserverInfo^.Observer.ReleaseSubject(IXPSubject(ObserverInfo.Subject),
ObserverInfo^.Context);
// Release our (list) reference to Observer
ObserverInfo^.Observer := nil;
System.Dispose(ObserverInfo);
FObservers.Delete(idx);
end;
FDeletingObservers := false;
end;
最佳答案
第二种方法是更明显的实现,它不关心线程安全。第一个是棘手的。
第一种方法使用临界区 FSync
为了线程安全。由于TXPSubject
是 TInterfacedObject
(在提供的代码中看不到),当删除对该对象的最后一个引用时,它将被销毁。这意味着当使用 DeleteObserver
删除最后一个观察者时调用 ReleaseSubject
在最后一个观察者上(应该将对主题的引用设置为 nil
),对象将被销毁。现在如果 ReleaseSubject
会在锁内被调用,那么该行
FSync.Leave;
FSync
)已被销毁。
ReleaseSubject
从锁中,创建观察者信息的本地副本
ObserverInfo := PXPObserverInfo(FObservers[idx])^;
FSync
之后锁已被释放,
ReleaseSubject
在该本地副本上调用。在那之后
Self
不再被引用,因此对象已被销毁并不重要。
DeleteObserver
仍然持有对
ISubject
的有效引用所以它不应该被破坏,直到这个引用超出范围。所以这个答案中描述的场景只有在观察者本身调用
DeleteObserver
时才会发生。 (可能在其析构函数中)在稍后由
ReleaseSubject
重新发布的引用上.
关于delphi - DUnit的XPObserver.pas中TXPSubject.DeleteObserver和TXPSubject.DeleteObservers有区别的原因?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/19938824/
我是一名优秀的程序员,十分优秀!