多线程正在减慢 OpenGl 循环

Multithreading is slowing down OpenGl loop

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

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

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

问题是我不明白为什么它使我的渲染变慢。即使我尝试创建 ONLY ONE 线程,我也会失去 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();
        }
    }

线程和进程在Linux下基本是一回事,都是在内部调用clone()创建的。所以你可以看到创建一个线程并不便宜,而且你在每个循环中都做了几次!

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

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

你可以自己写线程池as in this tutorial or ou can use a predefined pool as the one provided by boost::thread_pool

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