如何保持线程的对象实例化为线程外的事件足够长的时间?

时间:2012-03-04 01:15:40

标签: multithreading delphi events delphi-xe2

我正在研究一个多线程系统,该系统涉及线程通知其父级销毁对象。问题是,我需要允许该对象保持足够长的时间以使此事件读取此对象,因为我将对象作为事件参数之一传递。目前,当触发此事件时,传递给事件的对象已从线程内销毁。

我不希望线程必须等待才能完成此事件,而是知道何时触发此事件并然后销毁该对象。我希望线程中的代码无论如何都要继续,即使对象仍然被实例化。

有一个这些对象的列表,它们是在一个线程中创建的。当自己在这个列表中的对象发生某些事情时(特别是在这种情况下是对象的破坏),它自己具有事件的线程。我实际上是将这些事件提供给一个事件队列(一个TList,它包含指向什么事件和什么对象的记录指针)。所以在线程的某个地方,我向这个事件列表添加了一条记录。

线程的执行然后出现并循环遍历此列表中的事件并相应地触发它们(下面的示例)。因此,当事件被添加到列表中时,它将对象指针保存为此事件的记录指针的一部分。在实际触发事件之前可能会有很长的延迟。此时,对象仍需要实例化,以便可以从线程外部读取。只有这样,物体才会被摧毁。

用于此事件队列的机制没有任何反馈给线程的空间。它已经是一个已开发的系统,并且此事件队列的任何添加告诉线程事件已被触发是不可能的,因为它需要整个重写。否则,我会简单地告诉线程在我的事件被调用后销毁这个对象。

这是一些片段,系统实际上非常大,因此很难显示所有功能。一个线程的事件通过另外4个父对象引发一系列事件,将这个对象传递给每个对象。目标是防止线程之外的任何代码处理这种实际的破坏。在销毁之前,线程应该对等待此事件负全部责任......

type
  TJDNetSvrNode = class;
  TJDNetSvrThread = class;

  TNodeEvent = (neUnload); //And many more

  PNodeEventRec = ^TNodeEventRec;
  TNodeEventRec = record
    Event: TNodeEvent;
    Node: TJDNetSvrNode;
  end;

  TJDNetSvrNodeEvent = procedure(Sender: TObject; Node: TJDNetSvrNode) of object;

  TJDNetSvrNode = class(TObject)
    //Large object with no relevant members
  end;

  TJDNetSvrThread = class(TThread)
  private
    FNodeEvents: TList;
    FNodeEvent: PNodeEventRec;
    FOnNodeUnload: TJDNetSvrNodeEvent;
    procedure SYNC_OnUnload;
  public
    property OnNodeUnload: TJDNetSvrNodeEvent read FOnNodeUnload write FOnNodeUnload;
  end; //Much more in this class

//Starting point of event - adds to event queue list
procedure TJDNetSvrThread.NodeUnloaded(Sender: TObject; Node: TJDNetSvrNode);
var
  E: PNodeEventRec;
begin
  E:= New(PNodeEventRec);
  E.Event:= neUnload;
  E.Node:= Node;
  FNodeEvents.Add(E);
end;

//Called within thread to execute any events which are queued
procedure TJDNetSvrThread.ProcessNodeEvents;
begin
  while FNodeEvents.Count > 0 do begin
    FNodeEvent:= PNodeEventRec(FNodeEvents[0]);
    FNodeEvents.Delete(0);
    case FNodeEvent.Event of
      neUnload: begin
        Synchronize(SYNC_OnUnload);
      end;
      //And many more
    end;
    Dispose(FNodeEvent);
  end;
end;

procedure TJDNetSvrThread.SYNC_OnUnload;
begin
  if assigned(FOnNodeUnload) then
    FOnNodeUnload(Self, FNodeEvent.Node); //Parent also has to use "Node" for its event
  //NOW "Node" can be destroyed
end;

1 个答案:

答案 0 :(得分:5)

听起来你基本上想要的是一个对象能够从系统中的多个不同位置被引用,并且在所有引用它的地方完成之后不会被破坏,无论发生在什么顺序

Delphi有一种机制可以做到这一点:引用计数。它内置于Interface模型。尝试将对象转换为TInterfacedObject后代,创建并实现一个公开所需功能的Interface,然后传递它而不是对象引用。