Multithreading 带有delete[],dbgheap.c的MFC多线程
我有一个奇怪的问题,真的不明白发生了什么 我使用MFC多线程类使我的应用程序成为多线程的 到目前为止,一切正常,但现在: 在代码开头的某个地方,我创建了线程:Multithreading 带有delete[],dbgheap.c的MFC多线程,multithreading,mfc,Multithreading,Mfc,我有一个奇怪的问题,真的不明白发生了什么 我使用MFC多线程类使我的应用程序成为多线程的 到目前为止,一切正常,但现在: 在代码开头的某个地方,我创建了线程: m_bucketCreator = new BucketCreator(128,128,32); CEvent* updateEvent = new CEvent(FALSE, FALSE); CWinThread** threads = new CWinThread*[numThreads];
m_bucketCreator = new BucketCreator(128,128,32);
CEvent* updateEvent = new CEvent(FALSE, FALSE);
CWinThread** threads = new CWinThread*[numThreads];
for(int i=0; i<8; i++){
threads[i]=AfxBeginThread(&MyClass::threadfunction, updateEvent);
m_activeRenderThreads++;
}
m_bucketCreator
是一个静态成员。现在,在尝试删除缓冲区时,我在Bucket的解构器中发现了一些线程错误(然而,我理解这个缓冲区应该在这个线程的内存中,所以我不明白为什么会有错误)。在尝试删除[]缓冲区时,错误发生在dbgheap.c
中的\u CrtIsValidHeapPointer()
中
VisualStudio输出一条消息,它捕获了一个停止点,这可能是由于堆损坏,也可能是因为用户按下了f12(我没有;)
和类桶:
class Bucket : public CObject{
DECLARE_DYNAMIC(RenderBucket)
public:
Bucket(int a_resX, int a_resY){
resX = a_resX;
resY = a_resY;
buffer = new float[3 * resX * resY];
int buffersize = 3*resX * resY;
for (int i=0; i<buffersize; i++){
buffer[i] = 0;
}
}
~Bucket(void){
delete[] buffer;
buffer=NULL;
}
int getResX(){return resX;}
int getResY(){return resY;}
float* getBuffer(){return buffer;}
private:
int resX;
int resY;
float* buffer;
Bucket& operator = (const Bucket& other) { /*..*/}
Bucket(const Bucket& other) {/*..*/}
};
class Bucket:公共对象{
声明动态(RenderBucket)
公众:
Bucket(int a_resX,int a_resY){
resX=a_resX;
resY=a_resY;
缓冲区=新浮点[3*resX*resY];
int buffersize=3*resX*resY;
对于(int i=0;i您尚未创建私有复制构造函数或任何默认构造函数。如果类Bucket
是通过这些隐式定义的方法之一构建的,则缓冲区将被取消初始化,或者它将是复制构造函数创建的复制指针
类Bucket的复制构造函数是Bucket(constbucket&B)
——如果您没有显式声明复制构造函数,编译器将为您生成一个“朴素”的复制构造函数
特别是,如果分配、返回或以其他方式复制此对象,则复制构造函数将复制指向新对象的指针。最终,两个对象的析构函数将尝试删除[]相同的指针,第二次尝试将是双重删除,这是一种堆损坏
我建议您将类Bucket
的复制构造函数设置为私有,这将导致尝试的复制构造生成编译错误。或者,您可以实现一个复制构造函数,为复制的缓冲区
分配新空间
同样的情况也适用于赋值运算符,operator=
需要复制构造函数是:
<>这本书应该对所有C++程序员都是必读的。
如果您添加:
class Bucket {
/* Existing code as-is ... */
private:
Bucket() { buffer = NULL; } // No default construction
Bucket(const Bucket &B) { ; } // No copy construction
Bucket& operator= (const Bucket &B) {;} // No assignment
}
类桶{
/*现有代码原样*/
私人:
Bucket(){buffer=NULL;}//无默认构造
Bucket(const Bucket&B){;}//无复制构造
Bucket&operator=(const Bucket&B){;}//无赋值
}
重新编译,您可能会发现您的问题
还有另一种可能性:如果您的代码包含new
和delete
的其他用途,则这些分配内存的其他用途可能会损坏定义堆内存的链表结构。在调用delete
期间检测到这种损坏是常见的,因为deletee> 必须使用这些数据结构。您正在构造一个RenderBucket。您确定要从那里调用“Bucket”类的构造函数吗?它应该如下所示:
class RenderBucket : public Bucket {
RenderBucket( int a_resX, int a_resY )
: Bucket( a_resX, a_resY )
{
}
}
Bucket类中的初始值设定项将缓冲区设置为NULL是一个好主意…同时将默认构造函数和复制构造函数设置为私有将有助于双重确保它们未被使用。请记住..如果不使用,编译器将自动创建它们:
Bucket(); <-- default constructor
Bucket( int a_resx = 0, int a_resy = 0 ) <-- Another way to make your default constructor
Bucket(const class Bucket &B) <-- copy constructor
Bucket()以前所有的回复都是正确的。对于复制构造函数,请确保它不只是复制缓冲区指针,否则会导致问题。它需要分配一个新的缓冲区,而不是指针值,这会导致“delete”中出现错误。但我不认为复制构造函数会在代码中被调用
我查看了代码,没有发现任何错误。请注意,在这个GetNextBucket代码中甚至不需要线程同步,因为它返回一个局部变量,而这些变量是预线程
ValidateHeapPointer中出现错误是因为某些内容损坏了堆,当指针写入内存块时会发生这种情况。通常是for()循环走得太远,缓冲区分配得不够大,等等
调用“delete”时会报告此错误,因为此时在调试模式下验证堆是否存在错误。但是,在此之前已发生此错误,只是碰巧只在“new”和“delete”中检查堆。此外,它不一定与“Bucket”类相关
除了使用诸如BoundsChecker或HeapValidator之类的工具之外,要找到这个bug,您需要的是注释掉代码的各个部分,直到它消失,然后您就会找到有问题的代码
还有另一种方法可以缩小问题的范围。在调试模式下,在代码中包含,并在不同的关注点对_CrtCheckMemory()进行零星调用。这将在堆损坏时生成错误。只需移动代码中的调用,以缩小损坏开始发生的点
我不知道你使用的是哪个Visual C++版本。如果你使用的是VC++ 6的早期版本,那么你可以确保你在编译器选项中使用C运行时库的多TrimDLL版本。另一个线程?你想同步访问什么?我在顶部创建线程的地方添加了代码。m_bucketCreator是一个静态membervariable,可由多个ThreadsOry访问,这是一个键入错误。构造函数在那里-我只是将其命名为错误。现在我更正了错误。本例中的复制构造函数是Bucket(const class Bucket&B)您是否也处理了默认构造函数“Bucket()”?我真的不明白
class Bucket {
/* Existing code as-is ... */
private:
Bucket() { buffer = NULL; } // No default construction
Bucket(const Bucket &B) { ; } // No copy construction
Bucket& operator= (const Bucket &B) {;} // No assignment
}
class RenderBucket : public Bucket {
RenderBucket( int a_resX, int a_resY )
: Bucket( a_resX, a_resY )
{
}
}
Bucket(); <-- default constructor
Bucket( int a_resx = 0, int a_resy = 0 ) <-- Another way to make your default constructor
Bucket(const class Bucket &B) <-- copy constructor