# Multithreading for Games

This topic is 2500 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

## Recommended Posts

Hi everyone!

Is multithreading nessecary for real time 3d games, because I´ve always done it in the way to call update and paint in a loop without threading.

So my question: Do I need to/should use multithreading or is it better without it?

##### Share on other sites

As I noted above, fundamentally, for simpler games, if you have any respectable amount of disk access, you, at the very minimum, should have a disk access thread that processes all disk-read jobs and queues completed read jobs for another thread for parallel processing while it processes the next disk read task.

job2: create alpha channel or whatever (thread2)
job3: copy texture to GPU (draw thread)

All of these steps can be parallelized for multiple load operations. The real benefit kicks in once you realize that job1 can do much faster reads since all reads are more likely to be sequential (other applications less likely to interrupt disk heads) and you're effectively making use of HDD access (which is the slowest link in the sequence) 90+% of the time, effectively winning the time spend on job2 and job3.

Any further parallelization really depends on your game and the complexity you need. Overall I think a task-based system is a simple and elegant solution that will scale automatically the more cores/threads the system has while still having the ability to fall back to a single core/thread if only one is available.

##### Share on other sites

As I noted above, fundamentally, for simpler games, if you have any respectable amount of disk access, you, at the very minimum, should have a disk access thread that processes all disk-read jobs and queues completed read jobs for another thread for parallel processing while it processes the next disk read task.
I'd say "for simpler games" there's no need for multithreading at all. Unless perhaps on Atoms, but even those are going to run "simpler games" at interactive rates, albeit with some sweat.

Have you run into a performance wall with single-core, where you simply can't make your game run at interactive frame-rates?

If so, then you need to multi-thread your game.
Seconded. Given today's processors, I hardly believe a beginner can saturate them. Of course one can always do things wrong in the first place.

##### Share on other sites
[color=#282828][font=helvetica, arial, verdana, tahoma, sans-serif]

##### Share on other sites
@OP - if you're just a hobbyist learning how to make 3D games, I would not recommend trying to make a multi-threaded one first. It adds a lot more things to learn, and probably isn't necessary unless you really, really need 100% CPU utilisation from a quad-core...

Actually you may want more threads than cores. Consider a single-core cpu. It can still benefit from having multiple threads, especially if each thread is likely to block on something. If you have a single core, and 4 threads:
- game logic & render thread : constantly runs, 'interrupted' by occasional work in the other threads
- sound thread : will periodically do a 'spurt' of work processing audio every so often. most of the time it's waiting
- network thread : will spend most of its time blocked, waiting on a socket
- file thread: will spend most of its time either waiting for the game to ask to load something, or blocked on a slow disk operation
Generally speaking, your threads should not be likely to block on things. You should use non-blocking file-system and networking APIs, which removes the need for them to have their own threads (at a low level, these things are implemented asynchronously, using efficient methods such as DMA etc. The blocking APIs are a wrapper around things that are natively asynchronous, so if you then wrap up the blocking APIs with threads to make them asynchronous again, you've succeeded in adding two redundant layers of inefficiency to an operation that cancel each other out for zero benefit).
Also you usually don't create your sound thread yourself; it's usually created internally by your sound library and controlled via a non-blocking API.
So this just leaves the need for you to create your logic/rendering threads, which should simply just be your "one-thread-per-core general job/task processing" threads, which can run any logic/rendering/etc job (with rendering-submission jobs restricted to a specific thread if required).
On a modern OS, when a thread is blocked on something, such as waiting for the disk to read something, the kernel will set that thread aside, and run something in the another thread.[/quote]On windows, it also (by default) wont wake that blocked thread up for at least 15ms, even if it only needs to block for 0.5ms, which isn't very good for a real-time system, hence you should avoid blocking.
At the very minimum, multithreading is essential for fast resource loading...you have any respectable amount of disk access, you, at the very minimum, should have a disk access thread that processes all disk-read jobs and queues completed read jobs for another thread
As above, just use the OS's native asynchronous file APIs. You only need a background loading thread if you've got long-running post-load CPU work to do, such as LZMA decompression or XML parsing.

##### Share on other sites
On windows, it also (by default) wont wake that blocked thread up for at least 15ms, even if it only needs to block for 0.5ms, which isn't very good for a real-time system, hence you should avoid blocking.

This is really more for my sake than anything, but I was under the impression that this tidbit only held for explicit calls to Sleep(), and things like WaitForSingleObject() and friends can potentially be more responsive?

##### Share on other sites
Beside everything which has been said, there're two things I want to add.
1. Even with a single core CPU you already use a multicore system, that is CPU + GPU. You can utilize this by filling up the command queue of the GPU and then do some other tasks on the CPU. Until you don't use up this buffer (GPU is running, while CPU is idling) you don't need any multicore support (beside resource processing/loading).

2. When you want to add multicore support, you should start with it first. It is incredible hard to add multicore support later, some design decisions can easily steal the show (after writing 1000s of lines of gamelogic code in a scripting language like lua, it is somewhat demotivating to see, that lua doesn't support multicores in a single VM).

##### Share on other sites
This is really more for my sake than anything, but I was under the impression that this tidbit only held for explicit calls to Sleep(), and things like WaitForSingleObject() and friends can potentially be more responsive?
It doesn't matter how you transition a thread into a sleep state - once in that state, the kernel's scheduler won't come around and poke it back into a ready state until the next scheduling cycle, which defaultsto15ms on windows IIRC.
I actually should've said "up to 15ms", because if you go to sleep right before the next tick, you'll get woken up quickly (i.e. somewhere between 0ms to 15ms). However, if there's too many threads, a ready thread might not be chosen to execute in any given 15ms tick, other threads can cause starvation. After a thread has starved for 3-5 seconds, the kernel will give it a priority boost to ensure it gets to run for at least one tick. So any time you block (with default settings), you're sleeping for a best case of 0-15ms, and a worst case of ~4 seconds.

On a side note, [font=courier new,courier,monospace]Sleep(0)[/font] is allowed to immediately return instead of sleeping for a tick (which is usually bad), if thread priorities allow for it.

##### Share on other sites

It doesn't matter how you transition a thread into a sleep state - once in that state, the kernel's scheduler won't come around and poke it back into a ready state until the next scheduling cycle, which defaultsto15ms on windows IIRC.

Hmmm.. I use Sleep(1) in my multicore support code, after reading more about this topic it seems, that you can utilize the timeBeginnPeriod/timeEndPeriod to increase the timer resolution. As far as I understand, this will affect the whole OS (OS will take the highest resolution). Therefore I would try to encapsulate the sleep like this:
 timeBeginPeriod(1); Sleep(1); timeEndPeriod(1); 
Is this a bad idea (too much overhead, slowing down the OS) ?

1. 1
2. 2
Rutin
20
3. 3
khawk
16
4. 4
A4L
14
5. 5

• 11
• 16
• 26
• 10
• 11
• ### Forum Statistics

• Total Topics
633756
• Total Posts
3013707
×