Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/126.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 多线程和堆损坏_C++_Multithreading_Heap_Sfml_Corruption - Fatal编程技术网

C++ 多线程和堆损坏

C++ 多线程和堆损坏,c++,multithreading,heap,sfml,corruption,C++,Multithreading,Heap,Sfml,Corruption,所以我第一次开始尝试一些多线程编程,我遇到了堆损坏问题。基本上,在崩溃并抛出堆损坏错误之前,程序将随机运行一段时间(最短2秒,最长200秒)。我在这方面读到的每一篇文章都表明,诊断错误非常困难,因为引发错误的原因往往与导致错误的实际原因没有多大关系。因此,我仍然感到困惑 然而,我还没有正式学习过多线程,所以我主要是根据我对这个概念的理解来编程的,我的代码可能是完全错误的。下面是我要做的事情以及程序当前如何处理的基本概述: 我正在为一个简单的游戏编写代码,这个游戏需要绘制几个视差背景层。这些级别非

所以我第一次开始尝试一些多线程编程,我遇到了堆损坏问题。基本上,在崩溃并抛出堆损坏错误之前,程序将随机运行一段时间(最短2秒,最长200秒)。我在这方面读到的每一篇文章都表明,诊断错误非常困难,因为引发错误的原因往往与导致错误的实际原因没有多大关系。因此,我仍然感到困惑

然而,我还没有正式学习过多线程,所以我主要是根据我对这个概念的理解来编程的,我的代码可能是完全错误的。下面是我要做的事情以及程序当前如何处理的基本概述:

我正在为一个简单的游戏编写代码,这个游戏需要绘制几个视差背景层。这些级别非常大(例如20000x5000像素),因此显然尝试加载3层大小相同的图像是不可行的(如果不是不可能的话)。因此,目前图像被分割成500x500个图像,我有代码,只有它立即需要显示的图像保存在内存中。它加载的任何不再需要的图像都将从内存中删除。但是,在单个线程中,这会导致程序在等待加载映像后继续执行时显著挂起

在我看来,这就是多线程的逻辑所在。我希望程序能够在不影响游戏流畅性的情况下完成所需的加载,只要图像在实际需要时加载。我是这样组织的:

1.)图像应该放在哪里的所有数据以及与它们相关联的任何数据都存储在一个多维数组中,但最初没有加载图像数据。每一帧,代码都会检查阵列上的每个位置,并测试图像应该到达的位置是否在播放器的某个半径范围内

2.)如果是,则将此点标记为需要加载。指向图像应该加载到的位置的指针是push_back()'d到向量上

3.)第二个线程在级别开始时启动。该线程最初被传递一个指向上述向量的指针

4.)该线程被放入一个无限While循环中(它本身听起来是错误的),该循环仅在线程终止时终止。该循环持续检查向量中是否有任何元素。如果有,它将获取第0个元素,将图像数据加载到该指针中,然后.erase()从向量中删除该元素

这差不多就是它的工作原理。我未受过教育的假设是,两个线程在某个点上发生冲突,试图同时在同一个空间中写入和删除,或者做其他事情。考虑到我是新手,我确信这种方法在某种程度上是可怕的,所以我渴望听到我应该改进的地方

编辑:根据请求添加源代码:

类ImageLoadQueue
{
私人:
ImageHandle*图像;
std::字符串路径;
int frameWidth、frameHeight、numOfFrames;
公众:
ImageLoadQueue();
ImageLoadQueue(ImageHandle*a,std::string b,intc,intd,inte=1){setData(a,b,c,d,e);}
void setData(ImageHandle*a,std::string b,int c,int d,int e=1)
{
图像=a;
路径=b;
框架宽度=c;
帧高=d;
numOfFrames=e;
}
void loadThisImage(){image->loadImage(路径、帧宽、帧高、numoframes、numoframes);}
};
类ImageLoadThread:public sf::Thread
{
私人:
std::矢量*图像;
公众:
ImageLoadThread(){};
ImageLoadThread(std::vector*a){linkVector(a);}
void linkVector(std::vector*a){images=a;}
虚拟空运行()
{
而(1==1)
{
如果(!images->empty())
{
(*图像)[0]->loadThisImage();
图像->擦除(图像->开始());
}
}
}
};
班级艺术
{
私人:
int levelWidth、levelHeight、startX、startY、numOfLayers;
浮动宽度刻度、高度刻度、分段宽度、分段高度;
浮点*视差因子;
图像句柄**图像;
int**帧;
int**numOfFrames;
布尔*蒂莱耶;
bool**已加载;
动画数据;
std::string**imagePath;
向量图像队列;
ImageLoadThread imageThread;
公众:
LevelArt(无效);
LevelArt(标准::字符串);
~LevelArt(无效);
void loadData(std::string);
空图纸标高(sf::RenderWindow*,浮动,浮动);
无效缩放级别(浮动,浮动);
void forceDraw(sf::RenderWindow*);
void-level();
void initialLoad();
int getLevelWidth(){return levelWidth;}
int getLevelHeight(){return levelHeight;}
int getTotalWidth(){返回segs的宽度*levelWidth;}
int getTotalHeight(){return heightOfSegs*levelHeight;}
int getStartX(){return startX;}
int getStartY(){return startY;}
};
这就是本文标题中的大部分相关线程代码。在levelArt.cpp文件中存在3个嵌套循环,用于迭代存储的所有levelArt数据,测试它们是否离播放器足够近,以便显示,其中调用:

imageQueue.push_back(new ImageLoadQueue(&levelImages[i][(j*levelWidth)+k], imagePath[i][(j*levelWidth)+k], widthOfSegs, heightOfSegs, numOfFrames[i][(j*levelWidth)+k]));

i、 j,k是for循环迭代器。

这似乎是多线程的合理使用。关键思想(换句话说,如果你做错了,你会遇到问题的主要地方)是,你必须小心被多个线程使用的数据

您有两个地方拥有此类数据:

  • 向量(顺便说一下,它可能是一个队列)
  • 返回数据的数组
  • 安排事情的一种方法——绝不是唯一的方法——是将它们各自包装到自己的类中(例如,具有向量的成员变量的类)。不允许直接访问向量,只能通过类上的方法访问。然后同步这些方法,例如使用互斥体或任何适当的同步对象。请注意,您正在同步对对象的访问,而不仅仅是单个方法。因此,在“从队列读取”方法中放置互斥对象是不够的;在“readfro”中需要一个公共互斥体