如何同步线程与共享数据 С++

问题描述

我正在编写一个简单的 minecraft 克隆,我需要帮助。 我有一个实现“calculateMesh”和“createChunk”方法的“Chunk”类,第二种方法用特定的块类型填充块块字段,然后“calculateMesh”方法添加所需的边缘(如果块不是锁定或块不透明)。此外,块可以通过“World”类获取一个块的块,该类存储指向所有块的指针。为了形成正确的网格,所有块的 createChunk 方法必须完成。这两个操作都很繁重,如果添加了新块,它们会阻塞主线程。所以,我认为我需要在我的项目中添加一个线程池。我做的。但我不知道如何同步线程以避免当一个块试图获取一个未完成的块时出现错误 chun 。我认为所有块都应该等待 createChunk 方法完成,然后创建网格。我该怎么做?也许在我的线程池中使用优先级队列? (对不起我的英语:))

void Chunk::createChunk() {
    float heightP = 0.0;

    blocks = new Block[CHUNK_VOLUME];

    for (int x = 0; x < CHUNK_X; x++) {
        for (int z = 0; z < CHUNK_Z; z++) {
            glm::vec3 worldPos = toWorldPosition(glm::vec3(x,1.0f,z));

            heightP = perlin->noise(worldPos.x * 0.03f,worldPos.y * 0.8f,worldPos.z * 0.03f);

            for (int y = 0; y < CHUNK_Y; y++) {

                BlockType blocktype = StoneBlock;

                if (y > heightP * CHUNK_Y * 0.2f) {
                    blocktype = AirBlock;
                }

                addBlock(x,y,z,blocktype);
            }
        }
    }

    chunkReady = true;
}

void Chunk::calculateMesh() {

    if (hasMesh) {
        return;
    }

    vertices.clear();

    for (int x = 0; x < CHUNK_X; x++) {
        for (int z = 0; z < CHUNK_Z; z++) {
            for (int y = 0; y < CHUNK_Y; y++) {
                if (GetBlock(x,z).getBlockType() == StoneBlock) {
                    tryAddFace(x,BackFace);
                    tryAddFace(x,LeftFace);
                    tryAddFace(x,RightFace);
                    tryAddFace(x,FrontFace);
                    tryAddFace(x,TopFace);
                    tryAddFace(x,BottomFace);
                }
            }
        }
    }

    hasMesh = true;
}

Block& Chunk::GetBlock(int x,int y,int z) {
    if (outOfBounds(x,z)) {
        glm::vec3 pos = toWorldPosition({ x,z });
        return world->GetBlock(pos.x,pos.y,pos.z);
    }

    return blocks[getBlockIndex(x,z)];
}

解决方法

我认为您可以使用 std::async 来实现这一点。您应该将该函数绑定到 std::async 对象,该对象将异步调用它并返回未来的对象。当你得到未来的返回值时,它会被附加到主线程中。以下是示例用法:

#include <iostream>
#include <functional>
#include <future>

void foo()
{
    std::cout << "Hello async" << std::endl;  
}

int bar()
{
    return 15; // Your return type and value...
}

int main()
{
   std::future<void> f1 = std::async(std::bind(foo));
   std::future<int> f2 = std::async(std::bind(bar));
   
   f1.get();
   std::cout << f2.get() << std::endl;
   return 0;
}