1

I am trying to create an app, where the user can run a (time-consuming) backend physics simulation with the press of a button. But at the same time, I would like the rest of the GUI to remain functional and not to "freeze" until the simulation is over. Now I know that it is not a good idea to combine many threads for rendering in OpenGL, so my thought is rather simple : 1) Use one thread (I suppose the default one) to run everything apart from the physics. 2) Use another thread, only to run the physics which I have limited in one function as you will see. But even like this, the whole GUI still "freezes" and as a result it is useless until the physics ends. How can I fix that issue?

Below follows the code that I thought it would work. It renders a "Test button" in order to check if I can actually press it while the physics is running and the "Run physics" button that triggers a heavy computation.

#include"imgui.h"
#include"imgui_impl_glfw.h"
#include"imgui_impl_opengl3.h"

#include<GL/glew.h>
#include<GLFW/glfw3.h>

#include<cstdio>
#include<cmath>
#include<thread>

//Hypothetical "heavy" computation
void run_physics()
{
    for (double z = 0.0; z < 10000.0; z += 0.001)
    {
        double y = exp(sin(sqrt(z*abs(z)+ cos(z))));
    }
    return;
}

int main()
{
    glfwInit();
    glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
    glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
    glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);

    GLFWwindow *window = glfwCreateWindow(800,600, "Test", NULL, NULL);
    if (window == NULL)
    {
        printf("Failed to open a glfw window. Exiting...\n");
        return 0;
    }

    glfwMakeContextCurrent(window);

    glewExperimental = GL_TRUE;
    if (glewInit() != GLEW_OK)
    {
        printf("Failed to initialize glew. Exiting...\n");
        return 0;
    }

    IMGUI_CHECKVERSION();
    ImGui::CreateContext();
    ImGuiIO &io = ImGui::GetIO();
    (void)io;
    ImGui::StyleColorsDark();
    ImGui_ImplGlfw_InitForOpenGL(window, true);
    ImGui_ImplOpenGL3_Init("#version 330");

    glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
    while (!glfwWindowShouldClose(window))
    {
        glClear(GL_COLOR_BUFFER_BIT);

        ImGui_ImplOpenGL3_NewFrame();
        ImGui_ImplGlfw_NewFrame();
        ImGui::NewFrame();
        ImGui::Begin("Test");
        ImGui::Button("Test button");
        if (ImGui::Button("Run physics"))
        {
            //This pauses the render loop until run_physics is done. Good.
            //run_physics();

            //This also pauses the render loop. Why?
            std::thread thr(run_physics);
            thr.join();
        }
        ImGui::End();
        ImGui::Render();
        ImGui_ImplOpenGL3_RenderDrawData(ImGui::GetDrawData());

        glfwSwapBuffers(window);
        glfwPollEvents();
    }
    ImGui_ImplOpenGL3_Shutdown();
    ImGui_ImplGlfw_Shutdown();
    ImGui::DestroyContext();
    glfwTerminate();
    return 0;
}
genpfault
  • 51,148
  • 11
  • 85
  • 139
  • Does this answer your question? [Simultaneous Threads in C++ using ](https://stackoverflow.com/questions/24220778/simultaneous-threads-in-c-using-thread) – JaMiT Sep 18 '22 at 12:36
  • Not an unheard of problem. See also: [Launch a server and an IHM in different thread](https://stackoverflow.com/questions/24426632/) -- [threads does not work as I expect?](https://stackoverflow.com/questions/39001126/) -- [join() blocks continuation of main thread](https://stackoverflow.com/questions/23096928/) -- [std::thread please explain output](https://stackoverflow.com/questions/34078798/stdthread-please-explain-output) – JaMiT Sep 18 '22 at 12:39
  • Does run_physics use imgui to render anything? If it does, you could create two thread, and two imgui context – thedemons Sep 19 '22 at 14:32

1 Answers1

5

The problem is the thr.join() call, which will block until the thread exits.

There are a couple of ways to solve this. For example you can create an atomic status flag that is polled in the render thread. When the thread is done it sets the flag just before it exits. If the main rendering thread sees that the flag it set, then it calls the join call and fetches the result, which should happen pretty quickly.

Some programmer dude
  • 400,186
  • 35
  • 402
  • 621
  • Sorry for the looong delay. Though what you are proposing seems correct, it seems that by simply replacing thr.join( ) with thr.detach( ) fixes everything. Thanks for your time. – Michael Gaitanas Dec 17 '22 at 15:10
  • @MichaelGaitanas While a detached thread doesn't need to (and shouldn't) be joined, there are some flaws. For example, when your program exits then the thread might continue to run in the background while the rest of the program exits and all its resources are released. *Or* the whole process exits, which will forcibly and unexpectedly kill all your threads, detached or not. So you still need some way to synchronize the threads and their termination before your program ends. – Some programmer dude Dec 17 '22 at 15:55