繁体   English   中英

一种破坏TThread对象的正确方法

[英]A proper way of destroying a TThread object

这个问题似乎微不足道,但我希望你不要忽视它。
在销毁TThread对象之前,通常需要等到调用TThread.Execute()方法的线程完成,因为只有这样我们才能确定,例如,不再访问在类的析构函数中销毁的对象。 因此,有必要调用Terminate来设置线程必须检查的Terminated标志以知道是否退出,然后调用WaitFor()方法。

因为线程可能被挂起,我认为在调用WaitFor之前恢复它是好的,否则调用线程将会死锁。 并且因为线程可以多次挂起,所以应该恢复相同的次数,对吗?

while Suspended do
  Resume;

如果线程被创建为暂停,我们不必担心当我们恢复线程只会终止它时将调用TThread.Execute()方法 - 它不会(如果我错了请纠正我)。

我所说的建议为每个被释放的TThread对象使用以下代码行:

MyThread.Terminate;
while MyThread.Suspended do
  MyThread.Resume;
MyThread.WaitFor;
MyThread.Free;

不幸的是,当我们销毁创建多个线程的应用程序时,为每个被破坏的TThread对象编写这样一段代码会使代码变得非常长,甚至可能不透明。

因此,我得出的结论是,所有这些都可以放在TThread类的重写析构函数中,因为它可以调用MyThread.Free(如果设置了MyThread.FreeOnTerminate,则调用MyThread.Terminate),而不关心是否销毁object是否是TThread对象:

destructor TMyThread.Destroy;
begin
  //if FreeOnTerminate, the calling thread cannot wait for itself
  if GetCurrentThreadId <> ThreadId then
  begin
    Terminate;
    while Suspended do
      Resume;
    WaitFor;
  end;

  {free all objects created in this class}

  inherited Destroy;
end;

请原谅我提出这样一个基本问题。 但是,我希望通过这种方式了解您的意见 - 我希望这是一种普遍的方式 - 销毁TThread对象。 我问这个问题,因为我从我的同事的代码中了解到他们通常使用第一个代码示例来销毁这些对象,但他们从来没有用来检查等待的线程是否没有被挂起,如果线程我认为有点危险可能会在代码中的某处暂停。 因此,我试图找到一种破坏这个类的对象的通用方法,这将使代码更清晰,更安全。 我希望我没有让情况变得更糟 - 你怎么看?

提前感谢您的建议。

您的建议已经在TThread.Destroy析构函数中执行了很多,并且调用TMyThread.free将完成您的建议。 要清除线程类拥有的任何对象,可以在OnTerminate事件中执行该操作,该事件将作为线程关闭逻辑的一部分进行调用。

没有通用的方法来阻止线程,就像没有通用的方法(优雅地)停止进程一样。 每一个都是不同的。

对于某些线程,通过Terminate方法设置其Terminated属性就足够了。 但是,其他线程调用GetMessageMsgWaitForMultipleObjects类的函数,这些函数将阻塞直到发生某些事情,例如消息到达或内核句柄变为信号。 TThread.Terminate无法使这些事情发生,因此无法使这些线程停止运行。 当我写这些线程时,我提供了自己的函数来通知它们停止运行。 我可能会调用PostThreadMessage强制将消息强制到线程的队列中,或者我可能会发出线程类提供的事件来通知它终止请求。

不要担心恢复挂起的线程。 无论如何你真的不应该暂停它们。 挂起线程的唯一安全方法是让线程自行挂起,一旦你有了,你可以保证至少有两个线程控制线程运行的时间:线程本身暂停它,至少还有一个其他线程线程再次恢复它。 线程应该控制自己的执行。

如果TThread.Terminate是虚拟的,那将是很好的。 然后每个线程类都可以提供一种自定义方式来通知自己它应该停止运行。 有些人可以设置Terminated ,其他人可以发布自己的消息,信号事件,或做任何他们需要的事情。 但是,非虚拟方法对于花费大量时间等待其他事情的线程不能很好地工作。 当前方式仅适用于能够频繁轮询Terminated属性的线程。

某些线程设置了FreeOnTerminate属性。 对于那些线程,您的代码不安全。 从技术上讲,在这些对象上调用任何方法都是不安全的,因为线程可以随时终止。 但即使您知道线程仍在运行且线程对象仍然存在,该对象肯定会在调用Terminate之后的某个时间停止存在。 你不能在一个免费终止的线程对象上调用WaitFor ,你肯定不能调用Free

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM