VR-Forces 4.6 Class Documentation
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Groups Pages
Parallel Tick Component

This subclass of DtSimComponent shows the template of a thread safe component.


Header file:

/*******************************************************************************
** Copyright (c) 2016 MAK Technologies, Inc.
** All rights reserved.
*******************************************************************************/

#ifndef MyParallelTickComponent_H_
#define MyParallelTickComponent_H_

#include "vrfobjcore/simComponent.h"

class MyParallelTickComponent : public DtSimComponent
{
public:

   // "my-parallel-tick-component" - tag used in SMS.
   static const char* Tag;

   //constructor
   MyParallelTickComponent(
      const DtString& name, DtVrfObject* object, 
      DtSimManager* simManager, DtComponentDescriptor* compDescriptor, 
      DtReaderWriterRegistry* parentRegistry = 0);

   //Returns a string from compTypes.h, identifying the type of component
   virtual const char* type() const;

   //tick function
   virtual void tick();

public:

   //Creator function to be registered with the DtSimComponentFactory --
   //see main.cxx
   static DtSimComponent* creator(
      const DtString& name, DtVrfObject* object,
      DtSimManager* simManager, DtComponentDescriptor* compDescriptor,
      DtReaderWriterRegistry* parentRegistry);
};

#endif



Implementation:

/*******************************************************************************
** Copyright (c) 2010 MAK Technologies, Inc.
** All rights reserved.
*******************************************************************************/

#include "parallelTickActuator.h"
#include "vrfobjcore/simComponentTypes.h"
#include "vrfcore/simManager.h" 
#include "vrfobjcore/vrfObject.h"
#include "vrfcore/parallelTickManager.h"

const char* MyParallelTickComponent::Tag = "my-parallel-tick-component";

MyParallelTickComponent::MyParallelTickComponent(
   const DtString& name,
   DtVrfObject* object, 
   DtSimManager* simManager,
   DtComponentDescriptor* compDescriptor, 
   DtReaderWriterRegistry* const parentRegistry)
   : DtSimComponent(name, object, simManager, compDescriptor, parentRegistry)
{
}

const char* MyParallelTickComponent::type() const
{
   //This is string that will be used to register this actuator's creator function. If you want to make up 
   //your own name, then modify the .ope file for the affected entities
   //to reference the name of your new actuator. 
   //See chapter 6 of the VRForces Backend developer's guide for more information.
   return Tag;
}

// The parallel tick functionality uses a single global read write mutex to guard the entire
// global vrf state. Each object is ticked in its own thread, so it is guaranteed that no two
// components from the same object tick at the same time.
// All functions which read any vrf data are considered to read the global state
// unless explicitly stated otherwise. All functions that modify any vrf data are considered
// to mutate the global state unless explicitly stated otherwise. If an actuator is marked as
// thread safe (see the creator function) then it must use DtCriticalSection objects to mark
// sections of code with the type of access they need. This will only have an effect during the
// normal tick function call (because the parallel tick manager is enabled then). DtCriticalSection
// can still be used in code that is not called from tick, it just won't do anything.

// This tick function is a template for the most common form that a thread safe
// tick function takes, which consists of reading data from the global state, computing values
// from it, and then updating the global state with the new values.
// Not all tick function designs will work well with this form. Some components (like sensors)
// typically spend most of their time querying the global state, and then do more
// queries based on the results. In cases like this you usually do not want to unlock
// the shared lock between queries because it will result in a huge amount of mutex
// state changes which will usually result in poor performance. In general it is
// a bad idea to write an actuator which will change the state of the mutex many times.

void MyParallelTickComponent::tick()
{
   DtCriticalSection lock(simManager(), DtParallelTickManager::SHARED);

   // Read access to global VRF state allowed here.
   // Code here will not execute until no other code is modifying the global state, and any
   // code that wants to will have to wait until we are done.
   // Write access not allowed - do not change any global state.
   // Other components which are in the unlocked or shared state may
   // be running concurrently.
   // In this section components will usually read data they need from the global
   // state and copy it onto the stack.
   DtWarn("Accessing global state\n");

   lock.unlock();

   // No access to global VRF state allowed here.
   // Components can access (read and write) their ports (this is safe from anywhere).
   // Components can access the terrain interface and features.
   // In this section components will usually use the data they read in the previous step
   // to do expensive calculations (terrain intersections, feature queries).
   DtWarn("Parallel ticking\n");
   // Important Note: As soon as we release the lock, we cannot get it back without possibly
   // allowing other components to tick. This means that any data we've read from the global state
   // may have changed, because it has been ticked after we first looked at it. Care must be taken
   // so that only consistent data (i.e. all pre-tick or all post-tick) is used. The easiest way
   // to do this is to do all the reading you need up front and then only operate on data from 
   // the stack.

   lock.reset(DtParallelTickManager::EXCLUSIVE);
   DtWarn("Accessing global state\n");

   // Can read or write to any VRF state.
   // Only other components which are unlocked can run concurrently, they
   // may be doing thread safe operations like terrain intersections but
   // they will not be accessing any global VRF state.
   // In this section components will usually update the global VRF state with
   // the new values it has computed.
   // If the component is only updating ports then it does not (and should not)
   // have to get an exclusive lock.
}

// Passing the created component through the MarkThreadSafe function and
// returning the result is what turns on the parallel ticking functionality
// for this actuator. All actuators are created by default with this functionality off.
// This way base classes can be made thread safe while previously existing derived classes
// won't have to also become thread safe.
DtSimComponent* MyParallelTickComponent::creator(const DtString& name,
   DtVrfObject* vrfObject, DtSimManager* simManager, 
   DtComponentDescriptor* compDescriptor,
   DtReaderWriterRegistry* parentRegistry)
{
   return MarkThreadSafe(new MyParallelTickComponent(
      name, vrfObject, simManager, compDescriptor, parentRegistry));
}


Document ID: Generated on Thu Apr 12 03:15:37 EDT 2018 from SVN revision 187986
Copyright © 2005-2018 VT MÄK. All Rights Reserved (www.mak.com)