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

Mar*_*mke 16 delphi destructor tthread

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

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

while Suspended do
  Resume;
Run Code Online (Sandbox Code Playgroud)

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

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

MyThread.Terminate;
while MyThread.Suspended do
  MyThread.Resume;
MyThread.WaitFor;
MyThread.Free;
Run Code Online (Sandbox Code Playgroud)

不幸的是,当我们销毁创建多个线程的应用程序时,为每个被破坏的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;
Run Code Online (Sandbox Code Playgroud)

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

提前感谢您的建议.

ska*_*adt 8

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

  • @Mariusz:尝试编写没有Suspend()和Resume()的代码,你就不会遇到这个问题.这些方法可能非常有问题,正如您自己发现的那样,并且总有一种方法可以在没有它们的情况下进行编码.让线程阻塞一个或多个系统提供的同步原语.或者使用消息循环,在[delphi]中有关于多线程的信息有几个答案. (5认同)

Rob*_*edy 8

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

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

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

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

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