C++ 如何使我的组件实体系统线程安全?

C++ 如何使我的组件实体系统线程安全?,c++,entity-framework,boost,multithreading,components,C++,Entity Framework,Boost,Multithreading,Components,我目前正在集成一个实体组件系统,如图所示,带有一个物理引擎和一个图形引擎。这一切都很好,直到最近才决定物理应该按照自己的思路运行。(谢谢格伦·费德勒!) 现在,我只是在访问组件时锁定所有子系统共享的互斥锁 物理循环中的代码片段: lock_guard<mutex> lock( m_EntMutex ); entitymap::iterator it; for ( it = m_Ents.begin(); it != m_Ents.end(); ++it ) { // Get

我目前正在集成一个实体组件系统,如图所示,带有一个物理引擎和一个图形引擎。这一切都很好,直到最近才决定物理应该按照自己的思路运行。(谢谢格伦·费德勒!)

现在,我只是在访问组件时锁定所有子系统共享的互斥锁

物理循环中的代码片段:

lock_guard<mutex> lock( m_EntMutex );
entitymap::iterator it;
for ( it = m_Ents.begin(); it != m_Ents.end(); ++it )
{
    // Get physics component from entity
    // This is guaranteed to work ( component must exist for it to present in the map )
    shared_ptr<comp_phys> phys( static_cast<comp_phys*>( it->second->getComponent( COMP_PHYS ).lock().get() ) );
    // Get resulting Box2D vector
    b2Vec2 vec = phys->getBody()->GetPosition();

    // Get position component from entity
    // Same as above, but this is the component shared with the graphics subsystem   
    shared_ptr<comp_pos> pos( static_cast<comp_pos*>( it->second->getComponent( COMP_POS ).lock().get() ) );
    // Update position component from Box2D vector
    pos->setPosition( vec.x, vec.y, 0 );
}
lock\u guard lock(m\u EntMutex);
entitymap::迭代器;
for(it=m_Ents.begin();it!=m_Ents.end();+it)
{
//从实体中获取物理组件
//这保证可以工作(组件必须存在,才能在映射中显示)
共享物理(静态转换(it->second->getComponent(COMP_phys).lock().get());
//获取结果Box2D向量
b2Vec2-vec=phys->getBody()->GetPosition();
//从实体获取位置组件
//同上,但这是与图形子系统共享的组件
共享位置(静态转换(it->second->getComponent(COMP\u pos.lock().get());
//从Box2D矢量更新位置组件
位置->设置位置(向量x,向量y,0);
}
图形循环中的代码段:

lock_guard<mutex> lock( m_EntMutex );
entitymap::iterator it;
for ( it = m_Ents.begin(); it != m_Ents.end(); ++it )
{
    // Get position component from entity
    // This is shared with the physics subsystem
    shared_ptr<comp_pos> pos( static_cast<comp_pos*>( it->second->getComponent( COMP_POS ).lock().get() ) );
    // Get position from position component
    doubleVec3 vec = p->getPosition();

    // Get graphics component from entity
    shared_ptr<comp_gfx> gfx( static_cast<comp_gfx*>( it->second->getComponent( COMP_GFX ).lock().get() ) );
    // Update graphics component from position component
    gfx->getObject()->getParentSceneNode()->setPosition( float(vec.x), float(vec.y), float(vec.z) );
} 
lock\u guard lock(m\u EntMutex);
entitymap::迭代器;
for(it=m_Ents.begin();it!=m_Ents.end();+it)
{
//从实体获取位置组件
//这与物理子系统共享
共享位置(静态转换(it->second->getComponent(COMP\u pos.lock().get());
//从位置组件获取位置
doubleVec3-vec=p->getPosition();
//从实体获取图形组件
shared_ptr gfx(static_cast(it->second->getcomp(COMP_gfx).lock().get());
//从位置组件更新图形组件
gfx->getObject()->getParentSceneNode()->setPosition(浮点(vec.x)、浮点(vec.y)、浮点(vec.z));
} 
这显然是一个非常幼稚的实现,所以我尝试让各个组件都有自己的互斥体。这似乎是合乎逻辑的性能选择,但是物理结果(通过position组件查询)并不总是一致和可靠的

实现平滑更新过程的最有效方式是什么?我应该让它一次更新整个世界,还是做一些更增量的事情


编辑:我注意到指针获取方案存在缺陷,但是让我们假设指针是有效的。

当涉及到在游戏引擎中运行的物理引擎时,我建议您每帧有一个同步点,在那里您可以将物理系统中可能需要的位置/任何信息复制到组件系统中。如果你愿意,可以称之为“缓冲”。你位置的内部和外部实例(世界矩阵/速度等)

任何玩家都不会注意到物理位置最多一帧的延迟


另一方面,我更喜欢使用尽可能多的线程来实现物理引擎,而游戏引擎的其余部分最好什么都不做。Bullet和Havok似乎最适合这种解决方案

我应该补充一点,当你做同步点的时候,你想停止你的物理引擎的集成。我同意。拥有多个同步点可能看起来很有效,但在绘制场景之前仍然需要设置一个屏障,从而无法达到每个组件锁定的目的。还请注意,您通常希望让物理运行在与图形不同的帧速率上。我会专注于每次物理更新一个锁,并让游戏引擎从每个图形帧上最近的物理数据进行插值。