Beckman Institute            University of Illinois at Urbana-Champaign             
University of Illinois at Urbana-Champaign

Syzygy Documentation: Shared random numbers in the master/slave framework

Integrated Systems Lab
01/17/2006

Documentation Table of Contents

Background

The master/slave framework has a facility for generating pseudo-random numbers that is meant to be independent of whether it is called on a master or a slave. However, it is possible to use it in such a way that the random number sequences get out of sync for brief periods. This note describes its behavior and makes suggestions about how to avoid such errors. Please note that the framework will also detect such errors and print an error message to the console if they occur.

The following relevant data are transmitted from the master to the slaves on each frame:

  1. The current value of the random number seed. (_randomSeed)
  2. A flag indicating whether or not the seed has been set by the user. (_randSeedSet)
  3. The number of calls to the random number generator since the last data exchange. (_numRandCalls)
  4. The number generated by the last such call. (_lastRandVal)

    The slaves compare the transmitted values to their own using the following code:
        _randSynchError = 0;
        if (!_firstTransfer) {
          if (lastNumCalls != _numRandCalls)
            _randSynchError |= 1;
          if ((lastSeed != _randomSeed)&&(!_randSeedSet))
            _randSynchError |= 2;
          if (tempRandVal != _lastRandVal)
            _randSynchError |= 4;
        } else
          _firstTransfer = 0;
        _numRandCalls = 0;
    

    The next call to the random number generator checks _randSynchError and prints one or more error messages based on its value.

Functions

  void arMasterSlaveFramework::setRandomSeed( const long newSeed )

Sets the random seed on the master. The change does not take effect until immediately before the next data transfer, so it's probably not a good idea to start generating random numbers in e.g. the framework's init() callback. A value of 0 for the seed is illegal and will be converted to -1 with a printed warning.

  bool arMasterSlaveFramework::randUniformFloat( float& value )

Generates a new pseudo-random number using the ran1 //algorithm from //Numerical Recipes in C. Note that this algorithm generates uniformly-distributed values in the range (0,1), i.e. it does not include either 0 or 1. It returns a bool indicating whether or not _randSynchError is 0. As side-effects, it (1) resets _randSynchError to 0, so there is at most one error message per frame; (2) modifies the seed; (3) increments a counter, which is reset to 0 after each master/slave data transfer.

Getting into trouble

What follows is a list of conditions that we've thought of or come across under which the random number sequences will become desynchronized (mind you, the framework will tell you that you've gotten into trouble):

  • Calling randUniformFloat() in a way that depends on arMasterSlaveFramework::getMaster(). This function is designed to be used in exactly the same way on masters and slaves, so:
        if (framework->getMaster())
          dorandomstuff()
    
    is a Bad Thing.

  • Starting to call randUniformFloat() based on user input in the preExchange() callback. At this point, user input is only available to the master. For example:
        preExchange() {
          if (framework->getButton(0))
            startRandom = true;
        }
      
        postExchange() {
          if (startRandom)
            startusingrandomnumbers()
        }
    
    Is guaranteed to get you into trouble. Either move the code in preExchange() to postExchange() or use the library function ar_randUniformFloat() to generate random numbers on the master for manual sharing with the slaves.

  • Calling randUniformFloat() in more than one concurrent thread. Use ar_randUniformFloat() and share the generated data instead.

  • Calling randUniformFloat() before all program instances are running. Because Syzygy is designed around the premise that no program instance should care whether or not other instances are running (provided there is a master instance somewhere), this can only be determined by the user. The user should be required to indicate by e.g. a button press that all instances are running before randUniformFloat() is called.


[Schedule] [Labs] [Beckman Meeting Rooms] [Equipment] [Projects] [CUBE Projects] [Syzygy] [VSS] [People] [Events] [Publications]