首页 > 解决方案 > 多线程正在减慢 OpenGL 循环

问题描述

我目前正在使用 C++ 中的 OpenGL 编写类似于地图生成器的我的世界。我有一个 AMD Rayzen 5 3600 6 核。

因此,当我尝试在主循环中添加多线程来调用我的块生成时,它会减慢渲染速度。我没有使用多线程进行渲染

我在 Windows 上使用 MinGw 编译代码,多线程在 posix 上工作。

问题是我不知道为什么它会使我的渲染变慢。即使我尝试只创建一个线程,我也会失去 FPS。即使我创建了一个线程来执行简单的任务,例如:

std::cout << "Thread #" << i << "\n";

它会减慢渲染速度。

我的编译标志是-pthread -lopengl32 -lglu32 -lgdi32 -luser32 -lkernel32 -lglfw3dll -O3

我要补充一个事实,即在学校我正在使用 MacOS 并且多线程并没有减慢渲染速度。我假设一个MinGW问题。

如果您有任何想法可以帮助我,我会接受。感谢您即将做出的回应!

有我的循环:

while (!glfwWindowShouldClose(window))
    {
        Frustum frustum;
        //fps(window);
        float currentFrame = glfwGetTime();
        deltaTime = currentFrame - lastFrame;
        lastFrame = currentFrame;

        processInput(window);

        glClearColor(0.69f, 0.94f, 0.95f, 1.0f);
        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

        shader.use();
        glm::mat4 projection = glm::perspective(glm::radians(camera.Zoom), (float)SCR_WIDTH / (float)SCR_HEIGHT, 0.1f, 1000.0f);
        shader.setMat4("projection", projection);
        glm::mat4 view = camera.GetViewMatrix();
        shader.setMat4("view", view);
        frustum.Transform(projection, view);
        shader.setVec3("lightPos", glm::vec3(0.7, 0.2, 0.5));
        shader.setVec3("viewPos", camera.Position);
        displayChunk(shader, vox, &chunks, frustum);

        glDepthFunc(GL_LEQUAL); // change depth function so depth test passes when values are equal to depth buffer's content
        skyboxShader.use();
        view = glm::mat4(glm::mat3(camera.GetViewMatrix())); // remove translation from the view matrix
        skyboxShader.setMat4("view", view);
        skyboxShader.setMat4("projection", projection);
        // skybox cube
        glBindVertexArray(skybox.skyboxVAO);
        glActiveTexture(GL_TEXTURE0);
        glBindTexture(GL_TEXTURE_CUBE_MAP, skybox.cubemapTexture);
        glDrawArrays(GL_TRIANGLES, 0, 36);
        glBindVertexArray(0);
        glDepthFunc(GL_LESS); // set depth function back to default

        glfwSwapBuffers(window);
        glfwPollEvents();
        
        for (unsigned i = 0; i < 1; ++i)
        {
            threads[i] = std::thread([&mtx, i]
                                     {
                                         {
                                             // Use a lexical scope and lock_guard to safely lock the mutex only for
                                             // the duration of std::cout usage.
                                             std::lock_guard<std::mutex> iolock(mtx);
                                             std::cout << "Thread #" << i << " is running\n";
                                         }
                                     });
        }

        for (auto &t : threads)
        {
            t.join();
        }
    }

标签: c++multithreadingopenglcompilationminecraft

解决方案


线程和进程在Linux下基本上是一回事,都是通过内部调用clone()创建的。因此,您可以看到创建线程并不便宜,并且您在每个循环中都执行了多次!

不要为此而自责,第一代 Web 服务器 (Apache) 也是如此,对于每个连接,它们都会产生一个进程或线程。随着时间的推移,他们意识到只有创建进程/线程才是花费大部分时间的地方。创建进程或线程可能需要几毫秒。

下一个演变是线程池,这就是我建议你做的。您应该做的是预先创建所有线程并使用互斥锁和条件变量锁定它们。当您有工作要做时,您将数据推送到他们的队列或对象中并触发条件变量,这将解锁互斥锁并释放线程。这通常只花费您 3-10 微秒,这比您现在拥有的要好一千倍。

您可以像本教程中那样编写自己的线程池,也可以使用boost::thread_pool提供的预定义池。

如果你甚至发现 3-10 微秒太多了,你可以让你的线程以 100% cpu 旋转,并使用像boost spsc 容器这样的无锁容器进行通信。在这种情况下,线程之间的延迟下降到几十纳秒。这种方法的缺点是,即使什么都不做,你的线程也总是会消耗 100% 的内核。


推荐阅读