Я работаю над многопоточной системой, которая включает поток, уведомляющий своего родителя о разрушении объекта. Проблема в том, что мне нужно позволить этому объекту оставаться созданным достаточно долго, чтобы это событие могло прочитать этот объект, потому что я передаю объект в качестве одного из параметров события. В настоящее время, когда это событие инициируется, объект, который передается в событие, уже уничтожен из потока.
Я не хочу, чтобы поток обязательно ждал завершения этого события, но скорее знаю, когда это событие было инициировано, и затем уничтожит объект. Я хочу, чтобы код в потоке продолжался, несмотря ни на что, даже если объект все еще создается.
Есть список этих объектов, и они созданы из потока. Сам поток имеет события, когда определенные вещи происходят с объектами в этом списке (особенно в этом случае уничтожение объекта). Я на самом деле кормить эти события в очередь событий (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;