C++ OpenGL多线程
好的,我正在尝试将我的游戏引擎切换到多线程。我研究了如何在多线程应用程序中使用OpenGL。我在渲染或切换上下文方面没有问题。让我的代码来解释这个问题:): 这些属于此类的子类的命令具有_Execute()函数来执行任何需要执行的操作。渲染时主线程将填充这些命令的boost::ptr_向量,而辅助线程将继续检查是否有任何命令要处理。找到命令后,它会将整个向量复制到它自己的_AuxThread内的向量,并清除原始向量。然后,通过调用以下各项上的_Execute函数来执行命令:C++ OpenGL多线程,c++,multithreading,opengl,boost-asio,C++,Multithreading,Opengl,Boost Asio,好的,我正在尝试将我的游戏引擎切换到多线程。我研究了如何在多线程应用程序中使用OpenGL。我在渲染或切换上下文方面没有问题。让我的代码来解释这个问题:): 这些属于此类的子类的命令具有_Execute()函数来执行任何需要执行的操作。渲染时主线程将填充这些命令的boost::ptr_向量,而辅助线程将继续检查是否有任何命令要处理。找到命令后,它会将整个向量复制到它自己的_AuxThread内的向量,并清除原始向量。然后,通过调用以下各项上的_Execute函数来执行命令: void _AuxT
void _AuxThread()
{
//List of Thread commands
boost::ptr_vector<_ThreadCommand> _cmd;
//Infinitive loop
while(CORE_ENGINE->isRunning())
{
boost::lock_guard<boost::mutex> _lock(_auxMutex);
if (CORE_ENGINE->_ThreadCommands.size() > 0)
{
boost::lock_guard<boost::mutex> _auxLock(_cmdMutex);
for (unsigned int i = 0; i < CORE_ENGINE->_ThreadCommands.size(); i++)
{
_cmd.push_back(CORE_ENGINE->_ThreadCommands[i].Clone());
}
//Clear commands
CORE_ENGINE->_ThreadCommands.clear();
//Execute Commands
for (unsigned int i = 0; i < _cmd.size(); i++)
{
//Execute
_cmd[i]._Execute();
}
//Empty _cmd
_cmd.clear();
}
}
//Notify main thread that we have finished
CORE_ENGINE->_ShutdownCondition->notify_one();
}
void\u AuxThread()
{
//线程命令列表
boost::ptr_vector_cmd;
//不定式循环
同时(核心引擎->正在运行()
{
boost::lock\u guard\u lock(\u auxMutex);
如果(CORE_ENGINE->_ThreadCommands.size()>0)
{
boost::lock\u guard\u auxLock(\u cmdMutex);
for(unsigned int i=0;i\u ThreadCommands.size();i++)
{
_cmd.push_back(核心引擎->_线程命令[i].Clone());
}
//明确命令
CORE_ENGINE->_ThreadCommands.clear();
//执行命令
for(无符号整数i=0;i<_cmd.size();i++)
{
//执行
_cmd[i]。_Execute();
}
//空指令
_cmd.clear();
}
}
//通知主线程我们已经完成了
CORE_ENGINE->_ShutdownCondition->通知_one();
}
我知道这是一个非常糟糕的方法。执行速度相当慢,我很确定这是因为所有的复制和互斥锁。但至少渲染器可以工作。您可以了解我想要实现的目标,但正如我所说,我对多线程非常陌生。对于这种情况,最好的解决方案是什么?我是否应该使用asio::io_服务返回到线程池系统?如何将必须发送到渲染器的所有值馈送到AuxThread,以便以正确的方式执行任务?首先,警告。你的“小问题”一点也不小。它是竞争条件,它是C++中的未定义行为,这意味着任何可能发生的事情,包括:
- 一切都很好
- 图像闪烁
- 什么都没有
- 它在每个月的最后一个星期六崩溃。或者在你的电脑上工作得很好,在其他人的电脑上崩溃
核心渲染器->状态
复制到闭包中,并使用此副本进行渲染。但是,如果state
足够大,成本可能会很高
另一种解决方案(OpenGL就是这样做的)是将状态中的每一个更改也作为一个命令,所以
CORE_RENDERER->state.ModelMatrix = (*it).matrix;
CORE_RENDERER->state.ActiveSubmesh = (*it).submesh;
转化为
Matrix matrix = (*it).matrix;
Submesh submesh = (*it).submesh;
THREAD_POOL->service.post([&,matrix,submesh]{
CORE_RENDERER->state.ModelMatrix = matrix;
CORE_RENDERER->state.ActiveSubmesh = submesh;
});
但是,请注意,现在您不能简单地从主线程读取CORE\u RENDERER->state.ModelMatrix
,因为它正在另一个线程中更改。您必须首先确保命令队列是空的。使用std::future,您可以检查future是否准备好,并转到下一个迭代,而不是sleep。非常感谢:)我正在研究这个问题。但考虑到未来的一场突袭可能会消磨一点时间,这难道不会导致更慢的表演吗?我的想法是主线程继续准备命令,辅助线程渲染它们。当主线程完成并且辅助线程仍然渲染时,主线程可以执行其他操作,例如更新OpenAL音频流。我可能需要一个更好的解决方案,但我会试一试。非常感谢!!!:)希望您了解诸如lock、mutex、critical section、atomic operation等therm,也不要忘记对线程之间受影响的变量使用volatile
(有些编译器会忽略它们,有些编译器在没有它们的情况下根本无法工作,例如,我的AT32UC3芯片的GCC会为每个线程/ISR的每个全局变量进行本地复制,如果没有指定为volatile,我花了很多时间才发现……)。如果你没有足够的经验,我不会从无锁编程开始谢谢你的回答!我不确定我100%理解了你,但这样做也会对硬件造成危害?这是非常严重的!事实上,我是在3天前第一次涉足多线程领域的。正如你所说的,捕获状态,这就是我正在尝试做的。renderer使用基于材质/技术/过程的渲染,类似于OGRE。由于一个过程用于多个渲染器,我认为最好的方法可能是“捕获”有关所使用的过程、渲染的几何体和所有建模矩阵的信息。类似于复制渲染状态,但信息较少:)@Puso,硬件的问题是,但它仍然会以一种非常奇怪的方式给你带来麻烦,比如,升级到新的编译器、移植到新的平台或在你以外的计算机上运行时停止工作。这实际上是我对多线程最关心的问题之一!我担心,如果没有任何已知的原因,它将无法在所有机器上工作。所以,如果我想让它起作用,我需要小心。回到问题上来,实现这一点的最佳方法是存储有关过程的信息并将其用于渲染?有什么想法或文章吗
CORE_RENDERER->state.ModelMatrix = (*it).matrix;
CORE_RENDERER->state.ActiveSubmesh = (*it).submesh;
Matrix matrix = (*it).matrix;
Submesh submesh = (*it).submesh;
THREAD_POOL->service.post([&,matrix,submesh]{
CORE_RENDERER->state.ModelMatrix = matrix;
CORE_RENDERER->state.ActiveSubmesh = submesh;
});