VR-Forces 4.7 Class Documentation
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Groups Pages
5.10 - The Parallel Tick System

Table of Contents

The VR-Forces Parallel Tick System allows the tick functions of components to be run in parallel using multiple threads.

This can increase the sim tick rate and increase the number of entities the sim can manage. Components must be written in certain ways to take advantage of this feature. Enabling parallel ticking on components which do not use the thread safe APIs correctly can cause crashes.

Configuration

Parallel ticking is enabled for a given component by passing the component through the DtSimComponent::MarkThreadSafe function in the creator factory function for the component. This allows each specific class to be marked as thread safe without requiring that all classes derived from it are also marked (because they each have their own creator factory functions).

The entire system can be disabled with these vrfSim.mtl and/or command line options.

Writing Thread Safe Code

Components which are marked as thread safe need to use DtCriticalSection objects in order synchronize access with other component code which reads or manipulates the global state of the sim. DtCriticalSection works like a scoped guard for a mutex and will block to synchronize access to the global sim state. By creating DtCriticalSection objects on the stack, threads will block while other threads are taking action which cannot happen concurrently to whatever action the current thread wishes to take. The access type requested is specified in the AccessType parameter. If SHARED access is requested then the DtCriticalSection will block until there are no EXCLUSIVE access locks. If EXCLUSIVE access is requested then the DtCriticalSection will block until there are no SHARED or EXCLUSIVE locks.

The author of a thread safe component will have to know what functions can be called under what locking states which means understanding what is meant by the "global VR-Forces state". The global VR-Forces state is all the state data which does not have any kind of built in automatic thread synchronization. All functions which do have thread synchronization will be marked as thread safe. For example the terrain intersection query functions on DtTerrainInterface are all thread safe. Many of the global resource management singles are thread safe. An example of data which is not thread safe is the kinematic state of entities. If a component reads or changes these values without any sort of threading synchronization then there is nothing to prevent other components from doing the same concurrently in other threads, which leads to undefined behavior.

In order to correct this situation the component must use DtCriticalSection with the appropriate lock type. If data is being read then the access type should be SHARED so that other components can also read data concurrently. If state is being changed then the access type needs to be EXCLUSIVE. An important point to note is that all coherent data must be read during the same critical section state. This means that if you read the position and velocity of an entity you must do so without changing the access type in between. If this is not done correctly then you will sometimes read one value from tick t and the other value from tick t+1 which is not correct. If you component does a lot of reading then frequently this means leaving its access type at SHARED for the entire time, but you must remember that after you upgrade to EXCLUSIVE in order to set any state data, you cannot go back to reading.

A common pattern for many component types is to start off with a SHARED DtCriticalSection and read all the needed data into variables on the stack. Then unlock the DtCriticalSection entirely and do whatever calculations are necessary. At the end create an EXCLUSIVE DtCriticalSection and push the data into the global state. This will spend minimal time with EXCLUSIVE access which generally leads to the best performance. Remember that when the DtCriticalSection is unlocked you cannot access and data which may be accessed by other threads.

Components on the same entity are never ticked in parallel. This means that if some object is never accessed outside of component tick functions for the same entity then it does not need any synchronization access. For example ports are only accessed inside tick functions and are totally internal to a given entity. They are accessed by multiple components but since these components never tick in parallel, ports can be accessed at any point during component ticking regardless of the current access type. Data which is known to be constant also can be used without any kind of synchronization. For example component descriptors are never modified after they are created. This means they can be accessed by multiple threads concurrently without synchronization.

[<< Ports and Port Groups] [Home] [Top of Page] [Remote Attachment >>]


Document ID: Generated on Fri Apr 26 21:53:14 EDT 2019 from SVN revision 197883
Copyright © 2005-2019 VT MAK. All Rights Reserved (www.mak.com)