所以我刚开始第一次尝试一些多线程编程,我遇到了这个堆损坏问题。基本上,程序会运行一段随机的时间(短至 2 秒,长至 200 秒),然后崩溃并抛出堆损坏错误。我读到的关于这个主题的所有内容都表明它很难诊断,因为触发错误的原因通常与实际导致它的原因无关。因此,我仍然很难过。
然而,我还没有被正式教授多线程,所以我主要是根据我对这个概念的理解进行编程,我的代码可能完全错误。所以这是我正在尝试做的事情以及程序当前如何处理它的基本概要:
我正在为一个简单的游戏编写代码,该游戏涉及绘制几个视差层的背景。这些级别非常大(例如 20000x5000 像素),因此显然尝试加载 3 层这些大小的图像是不可行的(如果不是不可能的话)。所以目前图像被分割成 500x500 的图像,我的代码只有它需要立即显示的图像保存在内存中。它已加载的任何不再需要的图像都会从内存中删除。但是,在单个线程中,这会导致程序在等待图像加载后再继续时显着挂起。
这就是多线程对我来说合乎逻辑的地方。我希望程序完成它需要做的加载,而不影响游戏的流畅性,只要图像在实际需要的时候加载。所以这是我的组织方式:
1.) 图像应该去哪里的所有数据以及与它们关联的任何数据都存储在一个多维数组中,但最初没有加载图像数据。每一帧,代码都会检查数组上的每个位置,并测试图像应该去的位置是否在玩家的某个半径范围内。
2.) 如果是,则将此位置标记为需要加载。指向应该加载图像的位置的指针是 push_back()'d 到向量上。
3.) 第二个线程在关卡开始后启动。该线程最初被传递一个指向上述向量的指针。
4.) 这个线程被放入一个无限的 While 循环(这本身听起来是错误的),只有在线程终止时才会终止。这个循环不断检查向量中是否有任何元素。如果有,它会抓取第 0 个元素,将图像数据加载到该指针中,然后 .erase() 是向量中的元素。
这几乎是它如何工作的概要。我没有受过教育的假设是 2 个线程在某个时候发生冲突,试图一次在同一个空间中写入和删除或其他东西。鉴于我是新手,我敢肯定这种方法在某种程度上是可怕的,所以我很想听听我应该改进什么。
编辑:根据要求添加源代码:
class ImageLoadQueue
{
private:
ImageHandle* image;
std::string path;
int frameWidth, frameHeight, numOfFrames;
public:
ImageLoadQueue();
ImageLoadQueue(ImageHandle* a, std::string b, int c, int d, int e=1) { setData(a,b,c,d,e); }
void setData(ImageHandle* a, std::string b, int c, int d, int e=1)
{
image = a;
path = b;
frameWidth = c;
frameHeight = d;
numOfFrames = e;
}
void loadThisImage() { image->loadImage(path, frameWidth, frameHeight, numOfFrames, numOfFrames); }
};
class ImageLoadThread : public sf::Thread
{
private:
std::vector<ImageLoadQueue*>* images;
public:
ImageLoadThread() { };
ImageLoadThread(std::vector<ImageLoadQueue*>* a) { linkVector(a); }
void linkVector(std::vector<ImageLoadQueue*>* a) { images = a; }
virtual void Run()
{
while (1==1)
{
if (!images->empty())
{
(*images)[0]->loadThisImage();
images->erase(images->begin());
}
}
}
};
class LevelArt
{
private:
int levelWidth, levelHeight, startX, startY, numOfLayers;
float widthScale, heightScale, widthOfSegs, heightOfSegs;
float* parallaxFactor;
ImageHandle** levelImages;
int** frame;
int** numOfFrames;
bool* tileLayer;
bool** isLoaded;
Animation** animData;
std::string** imagePath;
std::vector<ImageLoadQueue*> imageQueue;
ImageLoadThread imageThread;
public:
LevelArt(void);
LevelArt(std::string);
~LevelArt(void);
void loadData(std::string);
void drawLevel(sf::RenderWindow*, float, float);
void scaleLevel(float, float);
void forceDraw(sf::RenderWindow*);
void wipeLevel();
void initialLoad();
int getLevelWidth() { return levelWidth; }
int getLevelHeight() { return levelHeight; }
int getTotalWidth() { return widthOfSegs*levelWidth; }
int getTotalHeight() { return heightOfSegs*levelHeight; }
int getStartX() { return startX; }
int getStartY() { return startY; }
};
这是此标头中的大部分相关线程代码。在 levelArt.cpp 文件中存在 3 个嵌套的 for 循环,用于遍历所有存储的 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 循环迭代器。