Take the 2-minute tour ×
Programmers Stack Exchange is a question and answer site for professional programmers interested in conceptual questions about software development. It's 100% free, no registration required.

This question already has an answer here:

I am programming a game engine as a hobby project, and I would like to separate physics and drawing into two separate threads. The position vectors of entities are subject to modifications by the physics thread, while the drawing thread only requires read access. In pseudocode:

Physics thread:
    loop
        ...
        read entity position
        compute new position for entity
        write entity position 
        ...
     end

Drawing thread:
    loop
        ...
        read entity position
        render entity
        ...
    end

Separating the drawing and physics into two threads allows for the decoupling of the physics update rate from the drawing framerate. This enables things like easy slow motion effects and variable frame rates, but also makes it possible for the physics thread to modify a position vector at the exact same time as the drawing thread is reading the same value.

I hope I could get away without using mutexes, locks or other concurrency controls for the position vectors. The validity of the position data is not critical, and small errors resulting from non-atomic access are tolerable. My experience with concurrent programming is however fairly limited, and I fear that there are other issues stemming from asynchronous access that I am not aware of. What are the drawbacks of this approach? What alternatives are there?

I am programming in C++11 (using std::thread), on a multi-core x86 PC.

share|improve this question

marked as duplicate by Kilian Foth, gnat, GlenH7, Dynamic, MichaelT May 8 at 0:33

This question has been asked before and already has an answer. If those answers do not fully address your question, please ask a new question.

    
Both questions sure are similar, but I am asking specifically about a data race, not a race condition: Are “data races” and “race condition” actually the same thing in context of concurrent programming. I would like to know specifically about what happens when a memory location is modified and read at the same time, something not addressed in the other post. –  jms May 6 at 7:44
    
code snippet in duplicate question addresses data race in the sense this question asks about: FLastUpdate "is modified and read at the same time" –  gnat May 6 at 8:00

1 Answer 1

up vote 3 down vote accepted

The suggested architecture does feature a data race. Whether this is negligible depends on the specifics of the game and on the details of the implementation. As the rendering thread can access the shared state at any time, this state must always be in a consistent, valid state.

For example, let's consider what might happen if the physics thread moves an object. If it first updates the x coordinate, then y and z, then between or during those updates the render thread may access the position. If our object is moved from (0, 0, 0) to (1, 1, 1), then the render thread might for example see the intermediate value (1, 0, 0). This is absolutely not a problem if for one frame the object appears two pixels to the left. But if your game features fast-moving objects or teleports across the map, then the result may be more noticeable.

How can this be avoided? The data must be updated atomically to provide a consistent view onto the state. For example:

  • The whole state is protected via a mutex. Either the physics thread has write access or the drawing thread has read access. As the physics thread always has read access, it can keep processing, and queue up a set of modifications to apply once it regains access. This is a suboptimal solution as the drawing thread may be locked out for a long time (compared with the intended frame rate).

  • The state of each game object is protected via a mutex. This makes it much less likely for the two threads to require access to the same object at the same time, but we now have to obtain many more locks which will also degrade performance. This solution can still feature smaller inconsistencies, such as two objects that seem to be intersecting on screen, but are actually only very close to each other, as at the time of drawing only one object has been updated.

  • The game state exists exclusively of pointers to various game objects. When an object has to be updated, first a copy of that object is created. Then, the changes are applied to the copy. Once the object is in a consistent state, the pointer to that object is atomically updated to point to the mutated copy. This solution can still feature minor inconsistencies, as with the previous solution. This could be implemented in terms of locks, but actually only an atomic update is required.

share|improve this answer

Not the answer you're looking for? Browse other questions tagged or ask your own question.