How can I multi thread this for loop?

  c++, multithreading, parallel-processing

I’m working with ImGui / ImPlot, and I want to speed it up by multi threading a for loop. I can’t understand how to debug this since ImGui displays an error when calling FreeWrapper, yet I can’t find out where it is even called. Regardless, I made a minimal reproducible example that demonstrates my problem. I apologise if its somewhat large, it’s the best I can do.

#include <GL/glew.h>

#ifndef GLFW_INCLUDE_NONE
#define GLFW_INCLUDE_NONE // GLFW including OpenGL headers causes ambiguity or multiple definition errors.
#endif // GLFW_INCLUDE_NONE

#include <GLFW/glfw3.h>

#include "ImGui/imgui.h"
#include "ImGui/implot.h"
#include "ImGui/implot_internal.h"
#include "ImGui/imgui_impl_glfw.h"
#include "ImGui/imgui_impl_opengl3.h"

#include <iostream>
#include <future>
#include <vector>


#define vecSize 5000


int main(int argc, char* argv[])
{

    char fps[10];
    std::vector< double > xData, yData;
    std::vector< std::future<void> > futures(vecSize);
    const char* glslVersion = "#version 460";


    glfwInit();

    // Create window with graphics context
    GLFWwindow* window = glfwCreateWindow(1280, 720, "Program", NULL, NULL);

    glfwMakeContextCurrent(window);
    glfwSwapInterval(0); //  vsync


    //Initialize GLEW + ImGui
    glewInit();

    // Setup Dear ImGui context
    IMGUI_CHECKVERSION();
    ImGui::CreateContext();
    ImPlot::CreateContext();

    // Setup Dear ImGui style 
    ImGui::StyleColorsLight();


    // Setup Platform/Renderer backends
    ImGui_ImplGlfw_InitForOpenGL(window, true);
    ImGui_ImplOpenGL3_Init(glslVersion);


    //srand(time(0));
    double randMax = 100;

    xData.resize(vecSize);
    yData.resize(vecSize);

    for (int i = 0; i < vecSize; i++) {
        xData[i] = 86400 * (double)i + 852163200;
        yData[i] = ((double)rand() / (double)(RAND_MAX)) * randMax;
    }


    while (!glfwWindowShouldClose(window))
    {

        //Events
        glfwPollEvents();


        // Start the Dear ImGui frame
        ImGui_ImplOpenGL3_NewFrame();
        ImGui_ImplGlfw_NewFrame();
        ImGui::NewFrame();


        ImGui::Begin("Graphs");

        if (ImPlot::BeginPlot("Bar Graph##Line", "Day", NULL, ImVec2(-1, 0), ImPlotFlags_NoLegend | ImPlotFlags_NoBoxSelect | ImPlotFlags_AntiAliased, ImPlotAxisFlags_Time, ImPlotAxisFlags_AutoFit | ImPlotAxisFlags_RangeFit)) {
            ImPlot::PushStyleColor(ImPlotCol_Line, ImVec4(0, 1, 0, 1));
            ImPlot::PushStyleColor(ImPlotCol_Fill, ImVec4(0, 1, 0, 1));
            for (int i = 0; i < xData.size(); i++) {
                futures[i] = std::async(std::launch::async, ImPlot::PlotBarVolume, "Bar Graph##Line Individual", xData[i], yData[i], 1, 86400 * 0.25);
            }
            ImPlot::PopStyleColor();
            ImPlot::PopStyleColor();
            for (int i = 0; i < futures.size(); i++) {
                futures[i].get();
            }
            ImPlot::EndPlot();
        }
        ImGui::End();


        //Fps checker
        sprintf_s(fps, "%.3f", ImGui::GetIO().Framerate);
        glfwSetWindowTitle(window, fps);
       

        // Rendering
        ImGui::Render();
        glClearColor(0.45f, 0.55f, 0.60f, 1.00f);
        glClear(GL_COLOR_BUFFER_BIT);
        ImGui_ImplOpenGL3_RenderDrawData(ImGui::GetDrawData());

        glfwSwapBuffers(window);

    }




    ImGui_ImplOpenGL3_Shutdown();
    ImGui_ImplGlfw_Shutdown();
    ImPlot::DestroyContext();
    ImGui::DestroyContext();


    glfwDestroyWindow(window);
    glfwTerminate();


    return 0;
}

In visual studio, to reproduce this, you will need to download and link the binaries for GLFW and GLEW, https://www.glfw.org/download , http://glew.sourceforge.net/ and then (for preprocessor settings) you need to add GLEW_STATIC. You also need ImGui and ImPlot, which are simple to integrate, https://github.com/ocornut/imgui https://github.com/epezent/implot . Also, last note for reproducing this, to get std::async to work with the function ImPlot::PlotBarVolume, I have modified and created a new function that just takes in the data as a reference to the individual values, rather a pointer to the entire array (so it lets me change the colours of each individual one), but it is exactly the same as the built in function ImPlot::PlotBars.

For the issue at hand (which I don’t know how to solve), this line here,

futures[i] = std::async(std::launch::async, ImPlot::PlotBarVolume, "Bar Graph##Line Individual", xData[i], yData[i], 1, 86400 * 0.25);

should be drawing a single "bar" on an overbearing "bar graph" each loop. I want to parallelised this to run faster, but I get a runtime crash. futures is a std::vector< std::future<void> > that is the same size as the iterations in the for loop. Why is this not working and how can I get it to a state where it is?

Source: Windows Questions C++

LEAVE A COMMENT