如何使线程在被释放之前完成工作? [英] How to make a thread finish its work before being free'd?

查看:91
本文介绍了如何使线程在被释放之前完成工作?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在写一个写事件日志的线程。当应用程序关闭(优雅)时,我需要确保此线程完成其作业保存日志,然后才能自由。如果我直接向线程调用 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 时,析构函数中会发生以下情况:


  1. 终止被调用。

  2. WaitFor 被调用。

  3. 线程的析构函数的其余部分然后运行。

换句话说,调用 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:

  1. Terminate is called.
  2. WaitFor is called.
  3. 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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆