0

I am building a map generator in C++ using glm, perlin, and std::future to generate chunks of a map. But for some reason, after some time, I get an empty future. I've tried to find some info about what does. It means if a future is empty and how to check it, but I came up with nothing.

Is there a way to check if a std::future is empty? Maybe someone can point out my mistake in code that creates this situation in the first place.

This is the exception thrown:

Unhandled exception at 0x7623D6C2 in VoxelEngine.exe:
Microsoft C++ exception: std::bad_alloc at memory location 0x00DDF290.

And here is the code:

void ChunkManager::update(float deltaTime)
{
    glm::vec3 cameraPosition = mainCamera->transform.getPosition();
    glm::i32vec3 newCameraChunk = cameraPosition / chunkSize;

    if (newCameraChunk != cameraChunk) {
        cameraChunk = newCameraChunk;
        loadChunks();
    }

    if (loading) {
        handleLoadingChunks();
    }
}

void ChunkManager::loadChunks()
{
    glm::i32vec3 minChunk(cameraChunk.x - visibleRange, 0, cameraChunk.z - visibleRange);
    float offset = Chunk::CHUNK_WIDTH * 2 * Block::BLOCK_SIZE;

    for (int x = 0; x < visibleRange*2; x++) {
        for (int z = 0; z < visibleRange*2; z++) {
            loadingChunks.push_back(std::async(std::launch::async, [&, x, z, minChunk, offset]() {return createChunk(x, 0, z, minChunk, offset, resourceManager); }));
        }
    }
    loading = true;
}

Chunk* ChunkManager::createChunk(int x, int y, int z, glm::i32vec3 minChunk, float offset, ResourceManager* resourceManager)
{
    Chunk* chunk = new Chunk(material, x + minChunk.x, y + minChunk.y, z + minChunk.z);
    chunk->InitializeChunk(noiseGenerator);
    chunk->CreateMesh(resourceManager);
    chunk->position(glm::vec3((x + minChunk.x) * offset, 0, (z + minChunk.z) * offset));
    return chunk;
}

void ChunkManager::handleLoadingChunks()
{
    bool allDone = true;
    for (auto& it : loadingChunks) {
        if (it.wait_for(std::chrono::seconds(0)) != std::future_status::ready) {
            allDone = false;
        }
    }

    if (allDone) {
        for (auto it : chunks) {
            delete it;
        }
        chunks.clear();

        for (auto& it : loadingChunks) {
            if (it.valid()) {
                Chunk* chunk = it.get(); // here i keep getting that it is empty. 
                chunk->FinalizeMesh();
                chunks.push_back(chunk);
            }
        }
        loadingChunks.clear();
        loading = false;
    }
}

class ChunkManager :
    public GameObject
{
public:
    ChunkManager(Material* material, Camera* camera, ResourceManager* resourceManager, NoiseGenerator* noiseGenerator);
    ~ChunkManager();

    void render(glm::mat4x4 projectionMatrix, glm::mat4x4 viewMatrix, glm::mat4x4 parentTransform);
    void update(float deltaTime);

private:
    std::vector<Chunk*> chunks;
    std::vector<std::future<Chunk*>> loadingChunks;

    glm::vec3 minCorner;

    glm::i32vec3 cameraChunk;

    void loadChunks();
    Chunk* createChunk(int x, int y, int z, glm::i32vec3 minChunk, float offset, ResourceManager* resourceManager);
    void handleLoadingChunks();

    float chunkSize;
    int visibleRange = 7;
    bool loading = false;
    Material* material;
    ResourceManager* resourceManager;
    NoiseGenerator* noiseGenerator;
};

enter image description here

EDIT

I think i found the possible cause for the error. But i dont know how to fix it. It seems to be that the Chunk object that is created in the future is tired to return to main thread but main thread is out of memory.

Marko Taht
  • 1,448
  • 1
  • 20
  • 40
  • 2
    https://en.cppreference.com/w/cpp/thread/future/valid – 463035818_is_not_an_ai Jun 14 '23 at 14:42
  • Missing declarations (data types) of the important variables. – Ben Voigt Jun 14 '23 at 14:50
  • @BenVoigt added header of ChunkManager. – Marko Taht Jun 14 '23 at 14:54
  • @463035818_is_not_a_number Does not work. already tried. – Marko Taht Jun 14 '23 at 14:55
  • 3
    what is the meaning of "does not work" ? And please read about [mcve]. The header you added just adds more undefined things. What is `GameObject`? What is `Material`? `Camera`? ... You should try to isolate the problem to a small example code – 463035818_is_not_an_ai Jun 14 '23 at 14:57
  • @463035818_is_not_a_number it.valid() does not check for empty state. as such it does not work to protect against it. Creating the example from the given code im unsure i can do that as i dont know what is causing the issue. I might remove the piece that causes the issue without knowing what i did. – Marko Taht Jun 14 '23 at 15:01
  • 2
    @MarkoTaht: What does "empty state" mean? `future::valid` is true if the future has a state. It either has state or it doesn't. – Nicol Bolas Jun 14 '23 at 15:03
  • If you just have `std::future f;` then `f.valid()` returns false. If that's what you mean by empty state. – ChrisMM Jun 14 '23 at 15:10
  • Do you want to test if the result has been set to the shared state? Something as discussed here? https://stackoverflow.com/q/52514850/580083 – Daniel Langr Jun 14 '23 at 15:13
  • ". I might remove the piece that causes the issue without knowing what i did." Thats why you should make it *complete*. Because only then you can compile and run the small example to make sure it does *reproduce* the issue. You can either reach that small example by incrementally removing parts from the actual one or by incrementally adding the a fresh one. The code you did post is not throwing an exceptio, because it does not compile – 463035818_is_not_an_ai Jun 14 '23 at 15:21
  • 1
    in the past it was called mcve - minimal complete verifiable example, not sure why the "complete" was dropped, maybe it is assumed to be already implied by "reproducible". In any case the code you posted is not sufficient to reproduce your issue – 463035818_is_not_an_ai Jun 14 '23 at 15:23
  • @ChrisMM i have std::future f; and im cheking it.valid(). But if f is empty it somehow passes throug hthe it.valid() check causing the error. There should never be a empty state. LoadChunks populates vector with futures and handleLoadingChunks waits for futures to complete and then collects them all. – Marko Taht Jun 14 '23 at 16:42
  • @NicolBolas check the image. it.get() is throwing an error because it has empty state. and right before it.get() there is it.Valid() check. – Marko Taht Jun 14 '23 at 16:43
  • @MarkoTaht: "*check the image.*" That just moves the question to VS. What does VS mean when it says that it is "empty"? "Empty" is not a term that is defined for a `future`. For all we know, "empty" might be how VS says that a particular `future` doesn't have a value yet. – Nicol Bolas Jun 14 '23 at 17:02
  • @NicolBolas im starting to think that hte fact that it is empty means that it has already been read. And the problem is not there. but instead its the std::bad_alloc that is happening for somereason... – Marko Taht Jun 14 '23 at 19:08

0 Answers0