【问题标题】:How can I multi thread this for loop?我怎样才能多线程这个for循环?
【发布时间】:2021-07-14 04:51:48
【问题描述】:

我正在使用 ImGui / ImPlot,我想通过多线程 for 循环来加速它。我无法理解如何调试它,因为 ImGui 在调用 FreeWrapper 时显示错误,但我什至无法找到它的调用位置。无论如何,我做了一个最小的可重现示例来演示我的问题。如果它有点大,我很抱歉,这是我能做的最好的。

#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;
}

在 Visual Studio 中,要重现这一点,您需要下载并链接 GLFW 和 GLEW 的二进制文件 https://www.glfw.org/downloadhttp://glew.sourceforge.net/,然后(对于预处理器设置)您需要添加 GLEW_STATIC。您还需要 ImGui 和 ImPlot,它们易于集成,https://github.com/ocornut/imguihttps://github.com/epezent/implot。另外,最后要注意的是,为了让std::async 与函数ImPlot::PlotBarVolume 一起工作,我已经修改并创建了一个新函数,它只接收数据作为对单个值的引用,而不是指向整个值的指针数组(所以它可以让我更改每个单独的颜色),但它与内置函数 ImPlot::PlotBars 完全相同。

对于手头的问题(我不知道如何解决),这里的这一行,

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

应该在每个循环的霸道“条形图”上绘制一个“条”。我想并行化它以更快地运行,但我遇到了运行时崩溃。 futures 是一个 std::vector&lt; std::future&lt;void&gt; &gt;,与 for 循环中的迭代大小相同。为什么这不起作用,我怎样才能让它达到它的状态?

【问题讨论】:

  • 我不确定您是否可以在对同一图像进行操作时正确并行化它。当您绘制线条时,您可能会修改相同的位置,这就是数据竞争。此外,画线主要是一种内存访问——在大多数 PC 中,单个内核几乎可以完全利用所有内存访问。只有像服务器级处理器是不同的野兽。
  • 我对 ImGUI 不太熟悉,但该错误可能是由于线程关联性造成的。基本上,只有实例化 OpenGL 的线程才有权访问它。可能有一些方法可以绕过它。
  • 函数接受对向量索引的 const 引用是否有帮助?因为那样每次循环时它总是在不同的点上?
  • 我已经使用 ImGui 对此进行了测试,根据我所做的,让多个线程启动某些 ImGui 绘制调用绝对可以。我不知道为什么,特别是因为我没有打电话给glfwMakeContextCurrent,但我测试的东西仍然有效,这就是为什么我进入下一个阶段,我想将它应用到一个 for 循环,使我的程序 FPS从 2000-3000 降至 50 左右
  • 你需要在所有期货返回后调用样式pop。此外,您启动了太多不好的异步操作。 5000太多了。您最多应该启动 8 个并在它们之间分配工作量。

标签: c++ multithreading parallel-processing


【解决方案1】:

我看过代码,你写的多线程是非常不安全的。

你推送了两次样式颜色,顺序异步操作,然后弹出样式颜色。并循环执行此操作。

您意识到异步操作可能会在更晚的时间点开始吗?怎样才能使用正确的色彩风格?或者如果它在主线程推送/弹出颜色样式时尝试使用它怎么办?这只是任意样式,以防ImPlot 是线程安全的,如果不是,则纯数据竞争。

此外,您在等待所有线条图完成之前触发ImPlot::EndPlot()

这是行不通的。

您必须查看 ImPlot/ImGUI 的文档,了解如何在多线程中完成所有这些工作,但我觉得它不支持任何多线程,但我可能会错误的。但是,它可能已经在幕后进行多线程处理,但我无法确定。

【讨论】:

  • 你能再看看吗。我重新编辑了应该以安全方式进行的问题。但是,仍然是相同的错误/崩溃。
猜你喜欢
  • 2014-06-18
  • 1970-01-01
  • 1970-01-01
  • 2020-01-05
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-08-14
  • 1970-01-01
相关资源
最近更新 更多