674 12. Collision and Rigid Body Dynamics
Running Physics in a Separate Thread
One option is to run the physics/collision engine in a dedicated thread.
As you might guess, this kind of design can lead to race conditions. If a
game object doesn’t update its game-driven rigid bodies in time, the physics
thread might end up using out-of-date locations in the simulation. Likewise,
if the simulation isn’t quite done by the time we want to update our physics-
driven objects, the game objects might end up using out-of-date locations as
well.
This problem can be solved by arranging for the physics and main threads
to wait for one another—a process known as thread synchronization. This is
done via mutexes, semaphores, or critical sections. Thread synchronization
is usually a relatively expensive operation, so we generally aim to reduce the
number of synchronization points between threads. In the case of the physics
engine, we need two synchronization points at minimum—one that allows
the physics simulation to begin each frame (aft er all game-driven rigid bodies
have been updated) and one that notifi es the main thread when the simulation
is complete (thereby allowing physics-driven bodies to be queried).
As part of a strategy to reduce synchronization points, communication
between threads is usually done via a command queue. The main thread locks
a critical section, writes some commands into the queue, and then quickly re-
leases it. The physics thread picks up the next batch of commands whenever
it gets the chance, again locking the critical section to ensure that the main
thread isn’t overwriting the queue during the read.
In the presence of collision queries , things get even more complicated.
To manage access to the collision/physics world by multiple threads, phys-
ics engines like Havok allow the world to be locked and unlocked separately
for reading and for writing. This allows collision queries to be performed at
any time during the game loop (during which the world is locked for read)
except while the physics world is being updated (during which it is locked
for write).
Fork and Join
The nice thing about a fork and join architecture for physics is that it essen-
tially eliminates all inter-thread synchronization issues. The main thread runs
as usual until the physics system needs to be stepped. Then we fork the step
off into separate threads (ideally one per processing core or hardware thread)
in order to execute it as quickly as possible. When all threads have completed
their work, the results can be collated, and the main thread can continue as in
the single-threaded case. Of course, for this to work, the physics system must
be designed to support fork and join. Most physics SDKs, including Havok