Getting into multi-threading.

Hello! I was digging around online and heard something about multi-threaded game loops. Right now mine are single-threaded, and I wanted to know if multi-threading them is the way to go. And if it is, how would I do it? I’m using LWJGL and OpenGL, so only one thread at a time can own the OpenGL context. Anyways, here are my questions:

  1. How big of an impact on performance would multithreading my game loop actually give me?
  2. How would I begin to learn how to make multi-threaded game loops having only used single-threaded ones?
    How many threads should I have? What should each of those threads do? etc, etc…

Also, on a sidenote, I’ve never really had enough textures loading at one time to need a loading screen, but if I did,
how would I load textures at the same time as the game loop running? (as only one thread can have OpenGL context at a time)

Thank you!

If I had to name one thing that one should not do just to do it, it would be multithreading.

My motto on the subject is if you don’t know what you would do with it, you probably shouldn’t use it.
For instance: “I want to multithread my game loop.” What exactly does that even mean? Do you mean compute physics or what have you on one thread and render on another? Why would you do that? You must at least have a reason and plan.

It sounds simple. “I’ll just multithread it.” But it’s not. Not at alllll. It’s actually quite horrible if you don’t know what your doing. And for what?

Be very, very careful when multithreading. It’s so easy to say “oh, this runs slow? MULTITHREAD IT!”. Multithreading has it’s places, but really, most of the development you’re probably doing doesn’t need it. I have multithreading in only one part of my entire current project, and that’s just the level loading so I can bring in the level a little faster. Because of how my game is setup, I probably could multithread other aspects of it. But I’ve found that I can make even my most CPU intensive stuff I currently use run plenty fast in a single thread.

(and this next part is me just guessing, based on the fact you claim never to have had a loading screen, so I apologize if I am wrong)
When it boils down to it though there’s a very, very good chance anything you currently want to multithread is running slow due to unoptimized code that could work better, not from you hitting the limits of what you can do on a single thread. Multitreading is very complicated, as pizza said, it sounds simple “I’ll just multithread it!”, but multithreading is really for very specific tasks and you can’t just throw multithreading at something to make it run faster. (Well you can, technically, but you’ll end up with tons of bugs unless you really know what you’re doing).

Thats true.

There are three possible results you can get with Multithreading:

1: If you are really into it and know what you’re doing, all is synchronized perfectly and the work is perfectly split to the Threads, it should be faster, at least on computers with more then one core.

2: If its not synchronized or not at the parts where it should be, it will just fail and crash or just do nothing or double work or show wrong results

2: If its bad synchronized and at wrong parts it will be slower then singlethreaded.

These are the reasons I only multithreaded my game loading process. It’s really a huge pain to multithread things inside your game loop from my experience. I’ve done it a few times, but I got so frustrated with all the issues with synchronizing I eventually just threw it out. :slight_smile:

You know what they say about optimization, especially of the premature variety. It’s the root of all evil. And ill-advised concurrency is the distilled essence of that. :point:

For a “suitable” use of concurrency that was not premature, perhaps have a look at this thing I made: https://github.com/BurntPizza/attractive
It’s not perfect of course, but try figuring out how it works. I think it’s fairly nifty. Play with the settings in Main, but watch for smoke coming out of your computer.

Note that nowhere in that code do I even touch raw Threads. They’re often not the tool for the job, and usually only cause pain.
EDIT: I am mistaken, I use one for the main loop. Ha!

If you’re serious, or at least want to know more about the interesting concept of concurrency, you can start here.

Look at the complexity of the average single-threaded game loop for something of moderate complexity and get back to me on how single threaded is easier.

Writing code that can be easily multithreaded is something that can be a bit difficult to get into, but once you get the hang of it it’s not hard at all. The problem usually lies in bug fixing, which is harder of course, but again it isn’t that hard if you learn to write manageable code.

Only thing I have ever used multi-threading for was pathfinding, even at that my map was not really big enough to warrant a separate thread for iterating through the open list.

The trick with multithreading is to have a fairly simple communication model with the data used in the treads. That is there is not a lot to synchronize because each thread is using almost 100% “thread local” data or immutable data. Commutation is done with a producer consumer queues. It works pretty well.

For a game… well i can’t really see it making much difference for an indie game. We are not talking AAA titles here and we are probably not overly taxing the GPU either. So a simple game loop may be all you need and it some make life very simple.

I run a game engine thread and a graphics thread and the are not synchronized. “Snap shots” of the state are sent to the graphics thread. Its quite a bit more complicated than normal game loop.

Our new game library is extensively multithreaded but only in very specific bits where it was possible to do without any synchronization and dependency. That was reasonably hard to do as it was and a pain to debug. It’s realised a very significant performance gain though, so it was worth it for us.

The bits we multithreaded were processing sprite animations, sorting sprites into the correct rendering order, writing sprite data out to VBOs, processing emitters, and processing particles; all of those things can be easily multithreaded without synchronization or effects on other parts of the game. That’s where most of our CPU time goes.

This is for dealing with >10k moving entities and >50k sprites though. Not many games really need those sorts of numbers.

Cas :slight_smile:

People with a decade or two of experience under their belt should not tell n00bs that multi-threading is ‘doable if you keep things simple’. It’s not doable at all, for them, yet - no matter how simple their use-case.

It still makes my brain bleed and dark patches form at the edges of my vision. It’s best avoided.

Cas :slight_smile:

If you need to ask, don’t.

Definitely , it is an important part of programming so give it a go… but do it first in a toy project you are not too committed to :slight_smile:

try something visual …

3 threads :

  • refresh a screen at 60 fps
  • draw a moving object at 30 fps
  • draw another moving object at 15 fps.

that should get you into trouble. :wink:

How much performance will you gain with multithreading? To give an example, I am working on making my game loop fully multithreaded. With my partly multithreaded game loop I could process 3000 AIs in 6ms. Now that I have fully multithreaded my game loop, I can handle those same 3000 AIs in 8ms. :frowning:

I like threads, they make great coding challenges, and are very rewarding when they work as expected.
They work best when there is very little data to exchange between them.

But in practice, I rarely need them.
They make the code more difficult to write, but also MUCH more difficult to maintain, because they add a new dimension of complexity to the code: we now not only have to worry about what the code is doing (what feature), where (in which class), and how (objects graph and collaboration), but also by whom (which threads). And its hard to see how threads work in a program just by looking at the code, they form a sort of hidden dimension.

It’s usually easier to optimize single-threaded code, or to multi-thread very specific parts of a program.

Thanks everyone. I didn’t really know what I was getting into. I didn’t even have a performance problem in the first place. I just thought that I’ll try and crank out as much speed as I can get for the hell of it. I’ll listen to the overwhelming majority of you and stay the hell away from multithreaded game loops because they are an endless pit of agony and despair. Buuuuuutttt, if we go back to my last question, isn’t having a separate thread for the loading process fine? And if so, how can I tame the OpenGL context to render my game and have a loading screen, whilst loading textures/shaders and things on the loading thread? But if having a second thread for loading isn’t how you’re supposed to do it then please, correct me again.

Making a separate thread for file reading/parsing is completely fine, in fact, that’s how you should do it.
You can use something like a callback system to keep track of which files are loaded already and increase the loading bar accordingly.
There are more “multithreaded OpenGL tricks” like texture streaming, but that’s a bit of an advanced topic, look into it if you feel like it. :slight_smile: