Issue
This Content is from Stack Overflow. Question asked by Michael Gaitanas
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.
Thank you in advance.
#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;
}
Solution
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.
This Question was asked in StackOverflow by Michael Gaitanas and Answered by Some programmer dude It is licensed under the terms of CC BY-SA 2.5. - CC BY-SA 3.0. - CC BY-SA 4.0.