Search code examples
c++multithreadingubunturenderingsdl-2

C++ threads cause issues on SDL2 rendering (since Ubuntu 23.10)


I noticed that my SDLD2/C++ application doesn't work properly or I changed nothing. So I tried to execute it on a Ubuntu 22.04 VM and it worked. After few tests, I noticed that if I take out my rendering function from the std::tread Tread function it reworks. But my program is now stucked when the "program" function is not finished.

Here is my code (in comment the previous thread implementation):

#include <SDL2/SDL.h>   
#include <array>
#include <cstdlib>    
#include <time.h>
#include <thread>
#include "const.hpp"
#include "maze_crea.hpp"
#include "maze_solver.hpp"

void program(SDL_Window* pWindow, SDL_Renderer* pRenderer){
    std::array<int, MAZE_SIZE<int>> maze;
    std::array<SDL_Rect, MAZE_SIZE<int>> squares;

    for (int i = 0; i < MAZE_SIZE<int>; i++){
        squares[i] = { (i % SIDE_SIZE<int>) * (WIDTHSCREEN<int> / SIDE_SIZE<int>), (i / SIDE_SIZE<int>) * (HEIGHTSCREEN<int> / SIDE_SIZE<int>), WIDTHSCREEN<int> / SIDE_SIZE<int>, HEIGHTSCREEN<int> / SIDE_SIZE<int> };
        if (((i % SIDE_SIZE<int>) % 2 == 0) || ((i / SIDE_SIZE<int>) % 2 == 0)){
            maze[i] = 0;
        } else {
            maze[i] = i;
        }
    }

    SDL_SetWindowTitle(pWindow, "Maze Solver (creation)");
    mazeCrea(pRenderer, maze, squares);
    SDL_SetWindowTitle(pWindow, "Maze Solver (solution)");
    mazeSolver(pRenderer, maze, squares);
}

int main(int argc, char* argv[])
{
     if (SDL_Init(SDL_INIT_VIDEO) < 0)
    {
        SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "[DEBUG] > %s", SDL_GetError());
        return EXIT_FAILURE;
    }

    SDL_Window* pWindow{ nullptr };
    SDL_Renderer* pRenderer{ nullptr };

     if (SDL_CreateWindowAndRenderer(WIDTHSCREEN<unsigned int>, HEIGHTSCREEN<unsigned int>, SDL_WINDOW_SHOWN, &pWindow, &pRenderer) < 0)
    {
        SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "[DEBUG] > %s", SDL_GetError());
        SDL_Quit();
        return EXIT_FAILURE;
    }

    srand(time(NULL));

    //std::thread Thread(program, pWindow, pRenderer);
    program(pWindow, pRenderer);

    SDL_Event events;

     while (true)
    {
         while (SDL_PollEvent(&events))
        {
            switch (events.type)
            {
            case SDL_QUIT:
                SDL_DestroyRenderer(pRenderer);
                SDL_DestroyWindow(pWindow);
                SDL_Quit();
                return EXIT_SUCCESS;
                break;
            }
        }
    }

    //Thread.join();

    SDL_DestroyRenderer(pRenderer);
    SDL_DestroyWindow(pWindow);
    SDL_Quit();

    return EXIT_SUCCESS;
}

How properly handle the case my "program" fucntion needs time but I want to be able to quit the app at any time so my event loop needs to be also accessible.


Solution

  • You need to separate the generation and solving code from the rendering. The simplest you can do is simply to cut the program in half, with a single shared variables between them to communicate the state.

    In this case, the state is really just maze.

    In your main loop, generate squares in advance. Then for every iteration of your game loop read the state from maze and update squares to match.
    In the thread, solve the maze and write the results back to maze or a secondary shared datastructure.