Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I make my component entity system thread safe?

I am currently integrating an entity component system, as seen here, with a physics engine and a graphics engine. This was all fine until recently deciding that the physics should be running in its own thread. (Thanks Glenn Fiedler!)

As it is now I am simply locking a mutex shared by all subsystems when accessing components.

Snippet from the physics loop:

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 );
}

Snippet from graphics loop:

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) );
} 

This is obviously a very naïve implementation, so I tried making the individual components have their own mutexes. It seemed the logical performance choice, but then the physics results (as queried through the position component) wouldn't always be consistent and reliable.

What would be the most efficient manner of accomplishing a smooth updating process? Should I let it update the entire world in one go or do something more incremental?

Edit: It has come to my attention that the pointer acquisition scheme is flawed, but let us assume that the pointers are valid.

like image 320
nilekurt Avatar asked Jul 24 '10 07:07

nilekurt


People also ask

How do you ensure thread safety in C++?

It's safe to read and write to one instance of a type even if another thread is reading or writing to a different instance of the same type. For example, given objects A and B of the same type, it's safe when A is being written in thread 1 and B is being read in thread 2.

How do you make a class thread safe in C#?

Lock provides the thread safety in multi-threaded application in C# . The lock keyword specified only one thread can be executed on at a time. when we use lock thread then only those line of code executed which is given in the scope of lock for specific thread.


1 Answers

When it comes to physics engines running in game engines I would suggest that you have a syncpoint once per frame where you copy over the positions/whatever information you might need from the physics system into your component system. Call it dubbel-buffering if you'd like. An internal and external instance of your position (world matrix / velocities etc).

Up to one frame delay on physics-positions is not something that any gamer will notice.

On another note, I prefer implementing physics engines in a way that use as many threads as possible while the rest of the game engine preferably does nothing. Bullet and Havok seem to work best with this solution.

like image 163
Simon Avatar answered Oct 30 '22 10:10

Simon