Game Multi-Threading

Started by
10 comments, last by shadowomf 11 years, 3 months ago
Well, what other types and how many threads should a game have?
Before thinking about multi-threading, you should reason about your memory-accessing patterns and if they are optimized enough. One thread with optimized/proper cache usage can often outweigh many threads using sloppy/improper cache usage.

Currently, I can think of no less than 4 distinct purposes/methods for multi-threading in games, and I am sure others can think of more.

1) Real-time processing. For faster response to input, Win32 messages, and the like, this processing often takes place in another thread. These threads usually require normal/high priority for fast response, although they are not active very long at a time (they sleep a lot due to inactivity).
2) Background processing. Asynchronous file loading, for instance, requires little processing power since this is an I/O-bound process. Asynchronous resource loading, on the other hand, may require a great deal of processing power when there are resources to load (and loading is not I/O-bound). But none of these tasks have to be carried out right away, so they usually have low/normal priority and will be processed when there are time to spare.
3) Scalable parallel processing. This can be rendering, physics simulation, logic processing, or any other task that can be divided into multiple smaller independent tasks, typically using task schedulers/pools (for queuing and delegation of tasks to worker threads), dependencies (tasks depending on other tasks or frame dependencies) and priorities for choosing the right order of processing. There is typically one global task scheduler and N+C worker threads, where N is the number of available hardware threads and C is some number for balancing the workload of worker threads (I have seen both -2, -1, 0 and 1, depending on the amount of processing the other threads have to perform). For reference, see http://threadingbuildingblocks.org/
4) Another popular solution for systems with few hardware threads (2-4) is to dedicate each thread to one/more subsystems and is often good enough when developing for a platform with a specific amount of threads (consoles, some mobiles, for instance). So for a 2-thread system you might have input, rendering and networking on one thread and physics and logic on another, but often one or more threads will have finished processing the current frame before the others and will have to wait (maybe not at first because it can process the next frame, but it cannot continue beyond X frames). This method can therefore lead to wasted cycles in waiting threads and is not scalable in itself.
Task schedulers, as explained in 3), address this problem by balancing the load amongst the available worker threads in order to avoid stalling any threads = no/less wasted cycles. This requires the work to be split into more-or-less equal-sized and independent tasks for optimal balancing and therefore optimum performance, though, and is therefore easiest to accomplish with something like physics, rendering and (depending on the management) logic.

I did not dive into the impact of different synchronization strategies, as others have already mentioned this.

Answer: A mix of all 4 methods is probably not a bad idea, but the answer should always be "it depends". You should consider the reason for each thread, its responsibilities, its impact on OS thread scheduling, and if the extra synchronization required, if any, is outweighed by the performance gains, also if any.
Advertisement

[quote name='Mr Purple' timestamp='1356538233' post='5014423']
Well, what other types and how many threads should a game have?
[/quote]

I wouldn't put one subsystem into one thread. And I wouldn't use one thread for just one thing (except where neccessary, e.g. to interact with libraries that are not completly thread-safe).

How about a thread pool and a job queue or tasks. Create as many threads as you find reasonable, e.g. number of threads = number of processor cores or whatever.

Add tasks too your queue. Whenever a thread is finished with one task a new task is fetched and executed.

Microsoft had once an interesting article/presentation about task level parallelism, but I couldn't find it at the moment.

I would certainly recommend you to use threads and learn how to use them, sure there is software that is single-threaded, but mostly for historic reasons or because the developer couldn't do it with threads. Adding threads at the end of development is probably of little use.

This topic is closed to new replies.

Advertisement