c++ - 多线程正在减慢 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();
}
}
解决方案
线程和进程在Linux下基本上是一回事,都是通过内部调用clone()创建的。因此,您可以看到创建线程并不便宜,并且您在每个循环中都执行了多次!
不要为此而自责,第一代 Web 服务器 (Apache) 也是如此,对于每个连接,它们都会产生一个进程或线程。随着时间的推移,他们意识到只有创建进程/线程才是花费大部分时间的地方。创建进程或线程可能需要几毫秒。
下一个演变是线程池,这就是我建议你做的。您应该做的是预先创建所有线程并使用互斥锁和条件变量锁定它们。当您有工作要做时,您将数据推送到他们的队列或对象中并触发条件变量,这将解锁互斥锁并释放线程。这通常只花费您 3-10 微秒,这比您现在拥有的要好一千倍。
您可以像本教程中那样编写自己的线程池,也可以使用boost::thread_pool提供的预定义池。
如果你甚至发现 3-10 微秒太多了,你可以让你的线程以 100% cpu 旋转,并使用像boost spsc 容器这样的无锁容器进行通信。在这种情况下,线程之间的延迟下降到几十纳秒。这种方法的缺点是,即使什么都不做,你的线程也总是会消耗 100% 的内核。
推荐阅读
- c++ - K-means 聚类中心每次运行都相同,尽管它是随机初始化的
- mean - emmeans 中所有预测的平均值
- c++ - 两个进程的 WinApi SpinLock 方法
- c# - Blazor - 此框架不支持“msxsl:script”元素,因为它不支持运行时代码生成
- javascript - 如何使用列表访问嵌套 json 中的数据?
- d3.js - 更改折线图中线条的颜色 vegalite
- c# - 简单发布并获取 C# WPF
- protocol-buffers - 编码和解码协议缓冲区任何类型的消息
- java - Spring如何处理需要参数的字段上的@Autowired?在这种情况下,JdbcTemplate 与 DataSource
- react-native - Detox - 应用程序卡在 iOS 的启动屏幕中