16

这个问题可能看起来微不足道,但我希望你不要忽视它。
在销毁 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 对象的方式(我希望是一种通用方式)的看法。我问这个问题是因为我从同事的代码中了解到,他们通常使用第一个代码示例来销毁此类对象,但他们从未使用过检查正在等待的线程是否没有被挂起,如果线程我认为有点危险可能会暂停在代码中的某处。因此,我试图找到一种销毁此类对象的通用方法,这将使代码更清晰、更安全。我希望我没有让事情变得更糟——你怎么看?

提前感谢您的建议。

4

2 回答 2

8

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

于 2009-07-06T22:49:17.450 回答
8

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

对于某些线程,通过方法设置其Terminated属性就足够了Terminate。然而,其他线程调用类似GetMessageor的函数MsgWaitForMultipleObjects,这将阻塞直到发生某些事情,例如消息到达或内核句柄发出信号。TThread.Terminate不能让这些事情发生,所以它不能让那些线程停止运行。当我编写了这样的线程时,我提供了自己的函数来通知它们停止运行。我可能会调用PostThreadMessage以强制将消息放入线程的队列,或者我可能会发出线程类提供的事件以通知它终止请求。

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

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

一些线程设置了它们的FreeOnTerminate属性。对于这些线程,您的代码不安全。从技术上讲,在此类对象上调用任何方法是不安全的,因为线程可能随时终止。但是即使您知道线程仍在运行并且线程对象仍然存在,该对象肯定会在调用Terminate. 你不能调用WaitFor一个终止时自由的线程对象,你绝对不能调用Free.

于 2009-07-07T14:57:22.720 回答