2009-07-06 70 views
15

这个问题可能看起来微不足道,但我希望你不会忽视它。
在销毁TThread对象之前,通常需要等到调用TThread.Execute()方法的线程完成后,才可以确保例如在类的析构函数内销毁的对象不再被访问。因此,有必要调用Terminate来设置线程必须检查的终止标志以确定是否退出,然后调用WaitFor()方法。
摧毁TThread对象的正确方法

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

while Suspended do 
    Resume; 

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

什么,我说建议使用下面的代码行对每个对象的TThread被释放:

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

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

因此我得出的结论是,所有这些都可以放在TThread类的overriden析构函数中,因为如果不关心,调用MyThread.Free(或MyThread.Terminate,如果MyThread.FreeOnTerminate设置)就足够了关于被破坏的物体是否是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对象。我问这个问题,我从我的同事们的代码中学到,他们通常使用第一个代码示例销毁这些对象,但他们从来没有用来检查被等待的线程是否被暂停,如果线程被认为有点危险可能会在代码中的某处暂停。所以我试图找到一种通用的方法来销毁这个类的对象,这会使代码更清晰和更安全。我希望我没有让事情变得更糟 - 你怎么看?

感谢您的建议提前。

+0

从哈姆雷特的主波洛尼斯的话提醒:简洁是机智的灵魂 – Argalatyr 2009-07-07 00:39:26

回答

8

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

+0

是的,这是真的,但是,我检查,只有当线程被创建暂停时,它是在调用析构函数时恢复。当我在工作中暂停它时,调用析构函数而不恢复它将导致死锁。这就是为什么我一直在寻找一种摧毁TThread对象的通用方式,对于任何从TThread继承的类都可以。 – 2009-07-07 06:23:46

7

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

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

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

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

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