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

Jer*_*dge 0 delphi events multithreading 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;
Run Code Online (Sandbox Code Playgroud)

Mas*_*ler 5

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

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

  • 是.为了避免这种情况,调用接口的`_AddRef()`方法在调用`PostMessage()`之前增加引用计数,然后让消息处理程序调用接口的`_Release()`方法来减少引用计数(不要如果`PostMessage()`失败,忘记调用`_Release()`. (2认同)