C++;多线程应用程序崩溃 我正在编写一个简单的3D渲染引擎,以便让C++更专业。今天,我开始了多线程处理的第一步,但已经遇到了一个无法解决的问题。当应用程序启动时,它会生成一个由立方体组成的类似地雷的小地形。它们是在主线程中生成的
现在当我想生成更多块时C++;多线程应用程序崩溃 我正在编写一个简单的3D渲染引擎,以便让C++更专业。今天,我开始了多线程处理的第一步,但已经遇到了一个无法解决的问题。当应用程序启动时,它会生成一个由立方体组成的类似地雷的小地形。它们是在主线程中生成的,c++,multithreading,c++11,dictionary,vector,C++,Multithreading,C++11,Dictionary,Vector,现在当我想生成更多块时 void VoxelWorld::generateChunk(glm::vec2 chunkPosition) { Chunk* generatedChunk = m_worldGenerator->generateChunk(chunkPosition); generatedChunk->shader = m_chunkShader; generatedChunk->generateRenderObject(); m_c
void VoxelWorld::generateChunk(glm::vec2 chunkPosition) {
Chunk* generatedChunk = m_worldGenerator->generateChunk(chunkPosition);
generatedChunk->shader = m_chunkShader;
generatedChunk->generateRenderObject();
m_chunks[chunkPosition.x][chunkPosition.y] = generatedChunk;
m_loadedChunks.push_back(glm::vec2(chunkPosition.x, chunkPosition.y));
}
void VoxelWorld::generateChunkThreaded(glm::vec2 chunkPosition) {
std::thread chunkThread(&VoxelWorld::generateChunk, this, chunkPosition);
chunkThread.detach();
}
void VoxelWorld::draw() {
for(glm::vec2& vec : m_loadedChunks){
Transformation* transformation = new Transformation();
transformation->getPosition().setPosition(glm::vec3(CHUNK_WIDTH*vec.x, 0, CHUNK_WIDTH*vec.y));
m_chunks[vec.x][vec.y]->getRenderObject()->draw(transformation);
delete(transformation); //TODO: Find a better way
}
}
我有我的成员函数(一切都是非静态的)generateChunk()
,它生成块并将其存储在VoxelWorld
类中。我有一个2Dstd::map m_chunks
存储每个块,还有一个std::vector m_loadedChunks
存储生成块的位置
调用
generateChunk()
工作正常。但是当我尝试generateChunkThreaded()
时,应用程序崩溃了!我试着注释掉generateChunk()
的最后一行,然后它就不会崩溃了。这就是让我如此困惑的原因m_loadedChunks
只是一个普通的std::vector。我试着把它公之于众,但没有效果。我有什么明显的遗漏吗 您正在从多个线程访问m_LoadedChunk,而不同步它。
您需要锁定共享用法的用法。这里没有什么提示
希望这对您有所帮助当您有许多线程访问共享资源时,您可以将这些资源设置为只读、原子或由互斥锁保护 因此,对于m_loadedChunks成员变量,您希望将其包装在锁中。例如:
class VoxelWorld
{
// your class members and more ...
private:
std::mutex m_loadedChunksMutex;
}
void VoxelWorld::generateChunk(glm::vec2 chunkPosition)
{
Chunk* generatedChunk = m_worldGenerator->generateChunk(chunkPosition);
generatedChunk->shader = m_chunkShader;
generatedChunk->generateRenderObject();
m_chunks[chunkPosition.x][chunkPosition.y] = generatedChunk;
{
auto&& scopedLock = std::lock_guard< std::mutex >(m_loadedChunksMutex);
(void)scopedLock;
m_loadedChunks.push_back(glm::vec2(chunkPosition.x, chunkPosition.y));
}
}
类体素世界
{
//你的班级成员和更多。。。
私人:
std::mutex m_loadedChunksMutex;
}
void VoxelWorld::generateChunk(glm::vec2 chunkPosition)
{
Chunk*generatedChunk=m_worldGenerator->generateChunk(chunkPosition);
generatedChunk->shader=m_chunkShader;
generatedChunk->generateRenderObject();
m_chunks[chunkPosition.x][chunkPosition.y]=generatedChunk;
{
auto&&scopedLock=std::lock\u guard(m_loadedChunksMutex);
(无效)scopedLock;
m_加载chunks.push_back(glm::vec2(chunkPosition.x,chunkPosition.y));
}
}
scopedLock将自动等待锁定,当代码超出范围时,锁定将被释放
现在请注意,我有一个用于m_loadedchunk的互斥锁,而不是一个覆盖线程可能访问的所有变量的通用互斥锁。这实际上是Herb Sutter在他的“有效并发”课程和在cppcon上的演讲中介绍的一个很好的实践
因此,对于您拥有的任何共享变量,请使用上述示例作为解决争用问题的一种方法。我甚至无法发现同步访问
m_chunks
或m_loadedChunks
的最小尝试。此外,避免在绘图循环中进行动态分配。@molbdnilo这是一个大问题吗?我是说在那种情况下这有什么关系m_loadedChunks
没有特定的顺序,m_chunks
是一个包含许多映射的映射。我知道我的抽签结果一团糟。这在我的待办事项清单上。你从哪里学习多线程编程?你可能应该为自己准备更好的学习材料。上网。我从来没有吃过比这更好的。好的,谢谢,我试试。但我为什么要把它锁上?@kiryu1。这里的代码太少,无法精确缩小程序崩溃的范围。缺乏并发防御是一个明显的问题,如果它不是当前bug的原因,那么它将成为未来的问题。2.使用互斥锁,但这样你可以得到范围解锁和更少的令人讨厌的惊喜。(待续)。你为什么需要这个?原因之一是:m_loadedChunks。当另一个线程正在迭代它时,push_back
可能会调整m_loadedChunks
的备份数据存储的大小。调整大小的一部分是删除和替换旧的数据存储,因此另一个线程正在查看的数据可能已经消失。它已被一个副本替换,但另一个线程无法知道这一点。您是对的,这是解决问题的第一步。对于lock_-guard,我将使用我的代码,这是真的,但我只缩进使用线程生成地形。至少现在是这样。我不知道这是否合适,但会有一个坏消息。在那里你也可以看到我的头文件。我现在正被这个该死的虫子压碎我的头!编辑此选项时不实际使用互斥。
class VoxelWorld
{
// your class members and more ...
private:
std::mutex m_loadedChunksMutex;
}
void VoxelWorld::generateChunk(glm::vec2 chunkPosition)
{
Chunk* generatedChunk = m_worldGenerator->generateChunk(chunkPosition);
generatedChunk->shader = m_chunkShader;
generatedChunk->generateRenderObject();
m_chunks[chunkPosition.x][chunkPosition.y] = generatedChunk;
{
auto&& scopedLock = std::lock_guard< std::mutex >(m_loadedChunksMutex);
(void)scopedLock;
m_loadedChunks.push_back(glm::vec2(chunkPosition.x, chunkPosition.y));
}
}