如何使线程在被释放之前完成工作? [英] How to make a thread finish its work before being free'd?
问题描述
Free
,那么它不应该立即被销毁,它应该等到线程完成,而且没有更多的工作要做。 这是我的线程的执行方式:
procedure TEventLogger。执行;
var
L:TList;
E:PEventLog; //自定义记录指针
begin
而不是终止do begin //重复持续直到终止
try
E:= nil;
L:= LockList; //获取锁定的日志记录
尝试
如果L.Count> 0然后开始//检查队列中是否存在任何日志
E:= PEventLog(L [0]); //从队列获取下一个日志
L.Delete(0); //从队列中删除日志
end;
finally
UnlockList;
结束
如果E nil然后开始
WriteEventLog(E); //实际调用保存日志
end;
除了
//处理异常...
end;
睡觉(1);
结束
结束
这里是析构函数...
析构函数TEventLogger.Destroy;
begin
ClearQueue; //我确定这应该被删除
FQueue.Free;
DeleteCriticalSection(FListLock);
继承;
结束
现在我已经知道,当 Free
被调用,我应该提出一个标志,使得不可能再添加任何更多的日志到队列 - 它只需要完成已经在那里。我的问题是,我知道上述代码将在线程空闲时被强制切断。
如果 Free
已被调用?或者如果这是不可能的,一般应该如何构造这个线程来实现这一点?
如果我直接向线程调用Free,那么它不应该立即被销毁,它应该等到线程完成,而且没有更多的工作要做。
我认为你对销毁线程会发生什么情况有点误解。当您在 TThread
上调用 Free
时,析构函数中会发生以下情况:
-
终止
被调用。 -
WaitFor
被调用。 - 线程的析构函数的其余部分然后运行。
换句话说,调用 Free
已经做了你所要求的,通知线程方法需要终止,然后等待它这样做。
由于您可以控制线程的执行
方法,因此您可以在检测到已经设置了终止的
标志。正如雷米所说,你可以覆盖 DoTerminate
,然后在那里做最后的工作。
对于什么是值得的,这是一种执行队列的糟糕方法。对 Sleep(1)
的调用直接跳到我身边。你需要的是一个阻塞队列。你清空队列,然后等待一个事件。当生产者添加到队列中时,会发出事件,以便您的线程可以唤醒。
I'm writing a thread which writes event logs. When the application is closed (gracefully), I need to make sure this thread finishes its job saving the logs before it's free'd. If I call Free
directly to the thread, it shouldn't immediately be destroyed, it should wait until the thread is done and there's no more work left to do.
Here is how I have my thread's execution laid out:
procedure TEventLogger.Execute;
var
L: TList;
E: PEventLog; //Custom record pointer
begin
while not Terminated do begin //Repeat continuously until terminated
try
E:= nil;
L:= LockList; //Acquire locked queue of logs to be written
try
if L.Count > 0 then begin //Check if any logs exist in queue
E:= PEventLog(L[0]); //Get next log from queue
L.Delete(0); //Remove log from queue
end;
finally
UnlockList;
end;
if E <> nil then begin
WriteEventLog(E); //Actual call to save log
end;
except
//Handle exception...
end;
Sleep(1);
end;
end;
And here's the destructor...
destructor TEventLogger.Destroy;
begin
ClearQueue; //I'm sure this should be removed
FQueue.Free;
DeleteCriticalSection(FListLock);
inherited;
end;
Now I already know that at the time when Free
is called, I should raise a flag making it impossible to add any more logs to the queue - it just needs to finish what's already there. My issue is that I know the above code will forcefully be cut off when the thread is free'd.
How should I make this thread finish its work when Free
has been called? Or if that's not possible, how in general should this thread be structured for this to happen?
If I call Free directly to the thread, it shouldn't immediately be destroyed, it should wait until the thread is done and there's no more work left to do.
I think you have a slight mis-understanding of what happens when you destroy a thread. When you call Free
on a TThread
, the following happens in the destructor:
Terminate
is called.WaitFor
is called.- The remainder of the thread's destructor then runs.
In other words, calling Free
already does what you ask for, namely notifying the thread method that it needs to terminate, and then waiting for it to do so.
Since you are in control of the thread's Execute
method, you can do as much or as little work there once you detect that the Terminated
flag has been set. As Remy suggests, you could override DoTerminate
and do your last pieces of work there.
For what it is worth, this is a poor way to implement a queue. That call to Sleep(1)
jumps right out at me. What you need is a blocking queue. You empty the queue and then wait on an event. When the producer adds to the queue the event is signaled so that your thread can wake up.
这篇关于如何使线程在被释放之前完成工作?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!