【发布时间】:2012-08-06 12:12:32
【问题描述】:
我有一个类,它有一个Start 方法来启动一个线程,该线程以预定义的时间间隔执行虚拟ThreadFunction。 Stop 方法设置一个事件并等待线程终止(通过线程句柄上的WaitForSingleObject)。
在MyThread的析构函数中,我调用了Stop方法。因此,每当我删除实例时,我确信线程在删除返回之前已停止。
class MyThread
{
void Start();
void Stop();
~MyThread() { Stop(); }
virtual VOID ThreadFunction() { }
};
接下来我有一个派生自MyThread的类:
class A : MyThread
{
virtual VOID ThreadFunction()
{
for (int i = 0; i < 1000; i++)
TestFunction();
}
void TestFunction() { // Do something }
};
考虑这段代码:
A a = new A();
a->Start();
delete a;
问题是delete a会先调用A的析构函数,然后再调用MyThread的析构函数,对吧?因此,如果线程正在执行ThreadFunction 中的for-loop,则Stop 方法将在a 被破坏后调用。当ThreadFunction 在已破坏的实例上调用TestFunction 时,这可能会导致访问冲突。
一种解决方案是向class A 添加一个调用Stop 方法的析构函数,如下所示:
class A : MyThread
{
~A()
{
Stop();
}
}
但是因为我有一个更复杂的类层次结构,它涉及多个继承的类,这意味着我必须在每个析构函数中调用 Stop 方法,这将导致 Stop 方法被调用很多次,而只有一个需要删除的实例。
还有其他方法可以解决这个问题吗?
【问题讨论】:
-
在删除类之前显式调用清理函数(在你的情况下停止),不方便,但我就是这样做的。我总是尽量在析构函数中放尽可能少的代码,只是因为你描述了析构函数的工作原理
-
这可能是大多数人不关心类似 Java 的线程类的原因。这个类有不止一个职责:它管理线程的生命周期和它执行的代码。把这两个关注点分开,一切都会变得容易。
-
实际上,
MyThread won't be called at all since it's notvirtual. If it was, then it would work fine since while the destructors are called the actual memory haven't been released yet, so e.g.this` 的析构函数在调用A析构函数的情况下仍然有效。不过您必须小心,因为成员变量可能已被释放和破坏,因此在调用A析构函数后访问它们可能会导致问题。 -
@JoachimPileborg:析构函数按照我在问题中描述的顺序调用,至少这是我的调试器在单步执行代码时告诉我的。并且析构函数没有定义为
virtual。
标签: c++ destructor