Separate physical thread without locks

I have a classic problem with physical flow and graphics:

Let's say I run one thread for physical updates and one thread for rendering.

In a physical stream (pseudo-code):

while(true)
{
  foreach object in simulation

     SomeComplicatedPhysicsIntegration( &object->modelviewmatrix);
     //modelviewmatrix is a vector of 16 floats (ie. a 4x4 matrix)
}

and in the graphics stream:

while(true)
{
  foreach object in simulation
    RenderObject(object->modelviewmatrix);
}

Now, theoretically, this will not require locks, since one stream only writes to matrices, and the other only reads, and I do not care about obsolete data.

The problem is that updating the matrix is ​​not an atomic operation, and sometimes the graphic stream will read only partially updated matrices (i.e. not all 16 floats were copied, only part of them), which means that part of the matrix is ​​from one physical frame and part from the previous frame, which, in turn, means that the matrix is ​​non-smooth affine (i.e. basically damaged).

? , , , .

. , , . - ?

2: , ( ). , , , .

, 1 . - :

:

while(true)
{
  foreach physicstimestep
   foreach object in simulation    
      SomeComplicatedPhysicsIntegration( &object->modelviewmatrix.WriteBuffer);
  LockSemaphore()
  SwapBuffers()
  UnlockSemaphore()
}

:

 while(true)
    {
     LockSemaphore()
      foreach object in simulation
        RenderObject(object->modelviewmatrix.ReadBuffer);
     UnlockSemaphore()
    }

?

+5
7

, .

, , . , . , , , , , .

- , (, ). , . , , .

+3

, , . , ( , , ).

, , .

, , , , , , - (, , , , , ). , , , - , - .

+5

, .

- , . , , . ( : ​​ .)

, , , . ( ), busy-wait on ( ).

( ) , , , . , .

, . , , .

+2

?

(, , ), //- . Invert/transpose/whateverCleverMatrixStuff modelviewmatrix , . . . , , , "" ?

, / /- ?

, /.

Rgds,

+1

, , - , .

: , - - . , , , .

+1

, , , , , , , , , , () () .

, , - :

/* pseudocode */
while (true) foreach (object in simulation) {
    auto new_object = object;
    SomeComplicatedPhysicsIntegrationInPlace(new_object)
    atomic_swap(object, new_object); // In pseudocode, ignore return value since nowhere
                                     // else changes value of object. In code, use assert, etc
}

Alternativelty, , . :

/* Psudocode */  while (true) {       simulation [1-global_active_idx] = simulation [global_active_idx];       foreach ( [global_inactive_idx]) {           SomeComplicatedPhysicsIntegrationInPlace ();       }       global_active_idx = 1-global_active_idx;// ,   }

[global_active_idx].

. , , , 1 , 0, , . , . , volatile, , .

, , , , , ++ ++ 0x, , " int" ARE , .

, , atomic_swap , (a) , , , , , , () , , . http://gcc.gnu.org/onlinedocs/gcc-4.1.2/gcc/Atomic-Builtins.html

, . , , 0 1; . ( ), , , .

, . - , , ? - , , , ? ?

+1

You can create two matrices in the same cache line size (128 bytes) and align it to 128 bytes. Thus, the matrix is ​​loaded into the cache line and, therefore, is written to and from memory in one block. This is not for the heart, although it will require much more work. (This only fixes the problem of reading the matrix during its updating and obtaining a non-orthogonal result.)

0
source

All Articles