Jump to content
  • Advertisement
  • entries
    205
  • comments
    228
  • views
    113469

Multi-threading fun

Sign in to follow this  
Mike Bossy

345 views

Since there's some interest in it I'll describe some of the multi-threading implementation I went with in my current code base. This is not the only way to do things and not necessarily the best way to do things. An ideal implementation would be extensible to handle a growing number of cores and be able to parallelize different things in different ways. There are a number of articles you can find online involving thread pools and such that will give other ways of doing things. Google is your friend.

I chose my current implementation out of the desire to not over engineer things. I was dealing with a small engine doing casual games. Performance gains were NOT my main goal of multi-threading. If anything it was to make things simpler, if it can be said that multi-threaded code is ever simpler. Add the fact that 99.9% of all machines still have only one core and you're going to need to get good enough perf on a single core.

The way I approached adding threads to my engine was to look at my main game loop and figure out which work items could usually be done in any order and not really affect the game. When I found one I put it on it's own thread to work at it's own pace.

A simple example works best to discribe this. Say you have a game that just is a physics simulation. All it does it update a bunch of objects based on a physics simulation and then renders them to the screen.

A simple game loop for that could be:


while (true)
{
UpdatePhysics(&CurrentScene);
Render(&CurrentScene);
}



where CurrentScene is just a scene graph of objects. Nothing weird here yet. So what would happen if we ripped the UpdatePhysics call out of that loop and had it on it's own thread?


// Running on main thread
while (true)
{
Render(&CurrentScene);
}

// Running on worker thread
while (true)
{
UpdatePhysics(&CurrentScene);
}



Most likely you wouldn't notice any difference at all in your simultation. Everything would probably look fine. The reality is that there are probably a number of small differences in the rendering of your simulation caused by multithreading goblins.

For example say you have an object which has an X and Y co-ordinate associated with it. These co-ordinates are updated by the physics thread and read by the render thread. The majority of the time these threads will be working on different objects in the scene, but occasionally you'll run across the scenario where both threads are working on the same object at the same time. That's where your little rendering differences will show up. Check out my quick little diagram below.

Bad Multi-threading goblins!

A is where our ball starts, B is where our ball is supposed to end up after our physics update, but C is where the ball is rendered if it is rendered after the Y co-ordinate is updated but before the X co-ordinate is updated. The good news is that your simulation layer is still correct and the next frame that is rendered will have the new updated position. What you need to decide in cases like this is if these differences will adversly affect your game. With a casual game these differences are minimal and don't affect gameplay so I just ignored them.

If you decide that you can't have these problems then you can solve then by using mutexes and the such. The ideal situation is to have zero data coupling between your threads but this is often hard to acheive.

Another way I added threading to my engine was to take some systems and make them message driven. For example my audio manager handles playing of all types of audio from simple play once wave files, midi files or streamed audio from something like an ogg file. It sits on it's own thread basically looking at a message queue checking for new work to do. The game code puts work in that queue for something like starting a streaming audio file. The audio manager starts the file playing and then handles updating the streaming buffer. This keeps it real simple for your game code to not have to deal with keeping track of what buffers need to be updated and when. Is it a performance gain? Probably not, but once again perf wasn't my only concern. I just made it easier for me to write my in game code. That is a tangible benefit.
Sign in to follow this  


2 Comments


Recommended Comments

I've actually considered a threading system built around a massive centralized message queue (the "spine") and a bunch of nanokernel-style threads that pick up and send messages.

Of course, I'll need to lock critical sections of data when threads are sharing data, but with some decent design I think this can be avoided (i.e. we can just have one thread that jams raw art assets into the renderer and another thread that sends out NPC update messages).

You could also just have threads that constantly send messages and one mega-thread that assembles and handles the messages, then renders the screen after it's received "enough".

Share this comment


Link to comment

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

We are the game development community.

Whether you are an indie, hobbyist, AAA developer, or just trying to learn, GameDev.net is the place for you to learn, share, and connect with the games industry. Learn more About Us or sign up!

Sign me up!