Multithreading slows down main thread - c++

I'll do my best to replicate this issue, since it's quite complicated. As an overview, I have a program that displays graphs using OpenGL. This is thread specific so I know the rendering is only done on one thread. My other thread queries a database and stores the data in a copy vector. Once the thread is finished, it swaps the data with the data the OpenGL thread is using (After joining the thread with the main one). In theory there is nothing about this that should make the program run so slow?
The extremely odd part of this is how it eventually "warms up" and runs much faster after a while (it varies quite a bit, sometimes almost instantaneously, sometimes after 30s of runtime). From value's side of thing to compare, the program begins running at about 30-60 fps whilst querying the data (as in, constantly loading it and swapping it and joining the threads), but then once it has warmed up it runs at 1000 fps.
I have tested some things out, beginning with making the query take A LONG time to run. During this, the fps is at a max of what it would be (3000+). It is only when the data is constantly being changed (swapping vectors) that is starts to run very slow. It doesn't make sense that this alone is causing the performance hit since it runs very well after it's "warmed up".
Edit:
I've managed to make a reasonable minimal reproducable example, and i've found some interesting result.
Here is the code:
#include <iostream>
#include <string>
#include <thread>
#include <GL/glew.h>
#include <GLFW/glfw3.h>
#include "ImGui/imgui.h"
#include "ImGui/imgui_impl_glfw.h"
#include "ImGui/imgui_impl_opengl3.h"
bool querying = false;
std::thread thread;
int m_Window_Width = 1280;
int m_Window_Height = 720;
static void LoadData()
{
querying = true;
std::this_thread::sleep_for(std::chrono::milliseconds(100));
querying = false;
}
int main()
{
glfwInit();
const char* m_GLSL_Version = "#version 460";
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 4);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 6);
GLFWwindow* m_Window = glfwCreateWindow(m_Window_Width, m_Window_Height, "Program", NULL, NULL);
glfwMakeContextCurrent(m_Window);
glfwSwapInterval(0); // vsync
glewInit();
IMGUI_CHECKVERSION();
ImGui::CreateContext();
ImGui::StyleColorsClassic();
// Setup Platform/Renderer backends
ImGui_ImplGlfw_InitForOpenGL(m_Window, true);
ImGui_ImplOpenGL3_Init(m_GLSL_Version);
thread = std::thread(LoadData);
while (!glfwWindowShouldClose(m_Window))
{
glfwPollEvents();
ImGui_ImplOpenGL3_NewFrame();
ImGui_ImplGlfw_NewFrame();
ImGui::NewFrame();
char fps[12];
sprintf_s(fps, "%f", ImGui::GetIO().Framerate);
glfwSetWindowTitle(m_Window, fps);
//Load the data
if (thread.joinable() == false && querying == false) {
thread = std::thread(LoadData);
}
//Swap the data after thread is finished
if (thread.joinable() == true && querying == false) {
thread.join();
}
// Rendering
ImGui::Render();
glfwGetFramebufferSize(m_Window, &m_Window_Width, &m_Window_Height);
glViewport(0, 0, m_Window_Width, m_Window_Height);
glClearColor(0.45f, 0.55f, 0.60f, 1.00f);
glClear(GL_COLOR_BUFFER_BIT);
ImGui_ImplOpenGL3_RenderDrawData(ImGui::GetDrawData());
glfwSwapBuffers(m_Window);
}
ImGui_ImplOpenGL3_Shutdown();
ImGui_ImplGlfw_Shutdown();
ImGui::DestroyContext();
glfwDestroyWindow(m_Window);
glfwTerminate();
return 0;
}
Now the interesting thing here is playing around with std::this_thread::sleep_for(). I have implemented this in so I can simulate the speed it actually takes when running the query on the main database. What is interesting is that it actually causes the main thread to stop running and freezes it. These threads should be separate and not impact one another, however that is not the case here. Is there any explanation for this? This seems to be the root issue for my main program and boiled down to this.
Edit 2
To use the libraries (in Visual Studio), download from here, the binaries, https://www.glfw.org/download.html and here aswell, http://glew.sourceforge.net/ and lastly, ImGui from here, https://github.com/ocornut/imgui
Preprocessor: GLEW_STATIC; WIN32;
Linker: glfw3.lib;glew32s.lib;opengl32.lib;Gdi32.lib;Shell32.lib;user32.lib;Gdi32.lib

This may or may not be your issue, but here:
//Load the data
if (thread.joinable() == false && querying == false) {
thread = std::thread(LoadData);
}
//Swap the data after thread is finished
if (thread.joinable() == true && querying == false) {
thread.join();
}
it is possible that you start the thread in the first if block, then get to the second one before LoadData modifies that bool, causing the wait for that tread to finish.
I would set querying = true; in the main thread, right after you created LoadData thread. Also, I would use some kind of synchronization, for example declare querying as atomic<bool>.
EDIT:
It appears that you do not need to check joinable() - you know when the thread is joinable: when you enter the loop, and after you re-start that thread. This looks cleaner:
std::atomic<bool> querying = true;
void LoadData()
{
std::this_thread::sleep_for(std::chrono::milliseconds(100));
querying = false;
}
and later in your loop:
//Swap the data after thread is finished
if (!querying) {
thread.join();
querying = true;
thread = std::thread(LoadData);
}

Related

Making a separate thread for rendering made my code slower

I had a method called run in which I am updating and rendering the game objects.
void Run(olc::PixelGameEngine* pge) noexcept
{
Update(pge);
Render(pge);
}
Frame rate then was fluctuating 300~400 frames in release mode and 200~300 frames in debug mode. I have yet to add lodes of game logic, so I thought I would do rendering in a separate thread, so after a quick tutorial later I changed it to this.
void Run(olc::PixelGameEngine* pge) noexcept
{
Update(pge);
std::thread renderer(&GameManager::Render, this, pge);
renderer.join();
}
Now the frame rate is around 100~150 frames in release mode and 60~100 frames in debug mode.
std::thread creates a thread.
renderer.join() waits until the thread has finished.
Basically the same logic as your first example, but you create and destroy a thread in your 'loop'. Much more work than before, not surprising that the framerate goes down.
What you can do:
define two functions, one for the update and one for the render thread
introduce an global atomic flag
set it in the update function (indicates scene has been updated)
clear it in the render function (indicates that the changes has been presented)
create a thread (runnable, either update or render)
if the scene gets updated, set the flag accordingly
the renderer can decide based on the flag to render the scene or wait until the scene gets updated or render anyway (clear the flag)
the updater can decide based on the flag to wait until the scene has been rendered or update it anyway
Example (c++11):
#include <atomic>
#include <thread>
atomic_bool active = true;
atomic_bool scene_flag = false;
void render(olc::PixelGameEngine* pge) noexcept
{
while (active) {
//while (scene_flag == false) //wait for scene update
renderScene(pge);
scene_flag = false; //clear flag
}
}
void update(olc::PixelGameEngine* pge) noexcept
{
while (active) {
//while (scene_flag == true) //wait for scene render
updateScene(pge);
scene_flag = true; //set flag
}
}
int main()
{
thread u(update, nullptr);
thread r(render, nullptr);
/*while (some_condition) ...*/
active = false;
u.join();
r.join();
return 0;
}
Note: The above code could/will update the scene while it is being rendered (could/will lead to several problems). Proper synchronization is recommended.

SFML thread synchronization?

I'm new to SFML, been trying to have a multi-threading game system (all of the game logic on the main thread, and the rendering in a dedicated thread using sf::Thread; mainly for practicing with threads) as explained in this page ("Drawing with threads" section):
Unfortunately my program has a long processing time during it's update() and makes the rendering process completely out of control, showing some frames painted and some others completely empty. If it isn't obvious my rendering thread is trying to paint something that isn't even calculated, leaving this epileptic effect.
What I'm looking for is to allow the thread to render only when the main logic has been calculated. Here's what I got so far:
void renderThread()
{
while (window->isOpen())
{
//some other gl stuff
//window clear
//window draw
//window display
}
}
void update()
{
while (window->isOpen() && isRunning)
{
while (window->pollEvent(event))
{
if (event.type == sf::Event::Closed || sf::Keyboard::isKeyPressed(sf::Keyboard::Escape))
{
isRunning = false;
}
else if (m_event.type == sf::Event::Resized)
{
glViewport(0, 0, m_event.size.width, m_event.size.height);
}
}
// really resource intensive process here
time = m_clock.getElapsedTime();
clock.restart().asSeconds();
}
}
Thanks in advance.
I guess the errors happen because you manipulate elements that are getting rendered at the same time in parallel. You need to look into mutexes.
Mutexes lock the element you want to manipulate (or draw in the the other thread) for as long as the manipulation takes and frees it afterwards.
While the element is locked it can not be accessed by another thread.
Example in pseudo-code:
updateThread(){
renderMutex.lock();
globalEntity.manipulate();
renderMutex.unlock();
}
renderThread(){
renderMutex.lock();
window.draw(globalEntity);
renderMutex.unlock();
}

Sharing opengl resources (OpenGL ES 2.0 Multithreading)

I have developed an OpenGL ES 2.0 win32 application, that works fine in a single thread. But I also understand that UI thread and a rendering thread should be separate.
Currently my game loop looks something like that:
done = 0;
while(!done)
{
msg = GetMessage(..); // getting messages from OS
if(msg == QUIT) // the window has been closed
{
done = 1;
}
DispatchMessage(msg,..); //Calling KeyDown, KeyUp events to handle user input;
DrawCall(...); //Render a frame
Update(..); // Update
}
Please view it as a pseudo code, cause i don't want to bother you with details at this point.
So my next step was to turn done into an std::atomic_int and create a function
RenderThreadMain()
{
while(!done.load())
{
Draw(...);
}
}
and create a std::unique_ptr<std::thread> m_renderThread variable. As you can guess nothing has worked for me so far, so i made my code as stupid and simple as possible in order to make sure i don't break anything with the order i call methods in. So right now my game loop works like this.
done.store(0);
bool created = false;
while(!done)
{
msg = GetMessage(..); // getting messages from OS
if(msg == QUIT) // the window has been closed
{
done.store(1);
}
DispatchMessage(msg,..); //Calling KeyDown, KeyUp events to handle user input;
// to make sure, that my problem is not related to the fact, that i'm rendering too early.
if(!created)
{
m_renderThread = std::make_unique<std::thread>(RenderThreadMain, ...);
created = true;
}
Update(..); // Update
}
But this doesn't work. On every draw call, when i try to somehow access or use my buffers \ textures anything else, i get the GL_INVALID_OPERATION error code.
So my guess would be, that the problem is in me calling glGenBuffers(mk_bufferNumber, m_bufferIds); in the main thread during initialization and then calling glBindBuffer(GL_ARRAY_BUFFER, m_bufferIds[0]); in a render thread during the draw call. (the same applies to every openGL object i have)
But I don't now if i'm right or wrong.

How do I interrupt xcb_wait_for_event?

In a separate thread (std::thread), I have an event loop that waits on xcb_wait_for_event. When the program exits, I'd like to shut things down nicely by interrupting (I have a solution that sets a thread-local variable, and checkpoints in the loop throw an exception), and then joining my event thread into the main thread. The issue is xcb_wait_for_event; I need a way to return from it early, or I need an alternative to the function.
Can anyone suggest a solution? Thanks for your help!
I believe I've come up with a suitable solution. I've replaced xcb_wait_for_event with the following function:
xcb_generic_event_t *WaitForEvent(xcb_connection_t *XConnection)
{
xcb_generic_event_t *Event = nullptr;
int XCBFileDescriptor = xcb_get_file_descriptor(XConnection);
fd_set FileDescriptors;
struct timespec Timeout = { 0, 250000000 }; // Check for interruptions every 0.25 seconds
while (true)
{
interruptible<std::thread>::check();
FD_ZERO(&FileDescriptors);
FD_SET(XCBFileDescriptor, &FileDescriptors);
if (pselect(XCBFileDescriptor + 1, &FileDescriptors, nullptr, nullptr, &Timeout, nullptr) > 0)
{
if ((Event = xcb_poll_for_event(XConnection)))
break;
}
}
interruptible<std::thread>::check();
return Event;
}
Making use of xcb_get_file_descriptor, I can use pselect to wait until there are new events, or until a specified timeout has occurred. This method incurs negligible additional CPU costs, resting at a flat 0.0% (on this i7). The only "downside" is having to wait a maximum of 0.25 seconds to check for interruptions, and I'm sure that limit could be safely lowered.
A neater way would be to do something like this (the code snippet is extracted from some code I am currently working on):
void QXcbEventQueue::sendCloseConnectionEvent() const {
// A hack to close XCB connection. Apparently XCB does not have any APIs for this?
xcb_client_message_event_t event;
memset(&event, 0, sizeof(event));
event.response_type = XCB_CLIENT_MESSAGE;
event.format = 32;
event.sequence = 0;
event.window = m_connection->clientLeader();
event.type = m_connection->atom(QXcbAtom::_QT_CLOSE_CONNECTION);
event.data.data32[0] = 0;
xcb_connection_t *c = m_connection->xcb_connection();
xcb_send_event(c, false, m_connection->clientLeader(),
XCB_EVENT_MASK_NO_EVENT, reinterpret_cast<const char *>(&event));
xcb_flush(c); }
For _QT_CLOSE_CONNECTION use your own atom to signal an exit and in my case clientLeader() is some invisible window that is always present on my X11 connection. If you don't have any invisible windows that could be reused for this purpose, create one :)
With this you can terminate the thread with xcb_wait_for_event when you see this special event arriving.

Gtk+ 3.0 Signal that trigger upon change in variable

I am trying to use Gtk 3.0 to visualize a network of nodes in real-time. The network of nodes will make new nodes and new connections will be formed between the nodes in real-time. I'm thinking of using one thread to configure Gtk and begin Gtk's main loop, and another for the development of the nodal network. The variables of the network will be global so that both the network developing thread and the Gtk thread can see the network variables. I will use a mutex on both sides to ensure synchronization.
My Gtk event-handler function will draw the current network, and idealistically, it should get called every time the network changes (eg new nodes, new connections). Therefore I would like to know if there is a solution in Gtk 3.0 where the event-handler function gets signaled every time a variable changes, say a change in vector's size, because I am using vector to store the nodes and connections.
I wrote a simple test program just to see if what I'm trying to do is possible. I have a thread which keeps incrementing an integer whereas another thread does all the Gtk configurations and initiates the main loop. In this code below, the Gtk thread draws the current value of the integer which keeps getting incremented. This code however is a modification of another and it does not draw the current value only at times when the value changes. Moreover, this code doesn't compile in Gtk 3.0. Is there any way to make this code compile in Gtk 3.0? In addition, is it possible to make it signal the drawing function only when the integer's value change?
#include <gtk/gtk.h>
#include <math.h>
#include <thread>
#include <mutex>
#include <string>
unsigned long long counter;
std::mutex mtx;
gboolean timeout(gpointer data) {
GtkWidget *widget = GTK_WIDGET(data);
if (!widget->window) return TRUE;
gtk_widget_queue_draw(widget);
}
gboolean expose(GtkWidget *widget, GdkEventExpose *event, gpointer data) {
cairo_t *cr = gdk_cairo_create(widget->window);
cairo_rectangle(cr, event->area.x, event->area.y, event->area.width, event- >area.height);
cairo_clip(cr);
cairo_set_source_rgb(cr, 0.1, 0.1, 0.1);
cairo_select_font_face(cr, "Purisa", CAIRO_FONT_SLANT_NORMAL, CAIRO_FONT_WEIGHT_BOLD);
std::string str;
mtx.lock();
str = std::to_string(counter);
cairo_move_to(cr, 20, 30);
cairo_show_text(cr, str.c_str());
mtx.unlock();
return FALSE;
}
void setupGtk() {
gtk_init(NULL,NULL);
GtkWidget *window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
g_signal_connect(GTK_WINDOW(window), "destroy",G_CALLBACK(gtk_main_quit), NULL);
GtkWidget *drawing_area = gtk_drawing_area_new();
g_signal_connect(drawing_area,"expose_event",G_CALLBACK(expose),NULL);
gtk_container_add(GTK_CONTAINER(window), drawing_area);
gtk_widget_show(drawing_area);
g_timeout_add(10, timeout, window);
if (!GTK_WIDGET_VISIBLE (window))
gtk_widget_show_all(window);
else {
gtk_widget_destroy (window);
window = NULL;
}
gtk_main();
}
void count() {
while(counter<100000000) {
mtx.lock();
counter++;
mtx.unlock();
}
}
int main(int argc, char *argv[]) {
std::thread gtk(setupGtk);
std::thread process(count);
gtk.join();
process.join();
return 1;
}
You will need to create your own GObject class and either add a signal to that that you can emit when the value changes or add a property to represent the variable and use the notify signal.
Note that signal emission is not guaranteed to cross thread boundaries properly. You will need to use gdk_threads_idle_add() to ensure the signal gets sent on he main thread.
If your goal is simply to redraw a control, you can call gtk_widget_queue_draw() or related in the idle callback instead of emitting a signal.
Note that an idle callback runs asynchronously. If you want the callback to complete before your other thread continues, you will need to write the synchronization method yourself.
(Sorry for the terse answer; I'm in a rush.)