Do Game Developers Need to Know Multithreading?

In a word, “yes.” But — there is always a “but!” — it depends on the type of game. AAA games (or as my wife puts it, the games that make the fans blow loudest) are highly demanding of resources and computing power. Browser games may not need quite so much grunt work to be playable. But let’s have some background first. What exactly is multithreading?

AA Game

Multithreading 101

It’s easier if we start with an old fashioned PC where the processor has only one CPU. It reads instructions from memory and then executes them. I’m simplifying this, as real CPUs have various memory caches and use strategies to keep these caches filled so they can run at top speed.

It’s like reading a fantasy adventure book. Every so often, you’re instructed to jump to another page and carry on from there. If someone interrupts you and says “play this other book for a while,” you put down your current book, perhaps bookmark or write down what page and paragraph you were on, and then start on the second book.

So when a CPU is interrupted, it saves out where it is in the code and the values of its registers, then starts executing another thread, loading all the pertinent registers and values. At some point it will switch back to the original thread of execution.

The important thing here is that a CPU can only execute one instruction at a time, just as we can only read one book at a time. (Yes, CPUs can do some floating point or integer operations at the same time, but let’s not confuse things.)

Since the CPU only does one thing at a time, you don’t necessarily gain any speed benefit from multithreading but it can be handy for making your PC responsive. Say your game needs to load up a large resource file into memory. For many games, it makes sense to bundle all the resources into compressed files and load them to minimize delays between chapters.

Disks transfer data hundreds of times more slowly than processors can read or write it. According to Wikipedia, a typical 7,200 RPM desktop hard disk can transfer data up to 1,030 Mbits/second, i.e., 128 MB/Sec, while the i7 950 (My PC’s Processor) can write at 25 GB/Second, approximately 200 times faster.

If the disk file is loaded in the main thread, it will freeze the GUI for a while, which is not a good thing. To make it responsive we need to load it in a background thread. That’s multithreading in use.

With the processor interrupted and switching threads to load data into memory, it uses less than 0.5 percent of its processing time. That leaves the Graphical User Interface responsive.

But most computers don’t have just one CPU these days. There are usually multiple cores contained in one chip, so we have to look at multicore programming.

Multi Cores

On my Windows 7 PC, the Task Manager tells me that there are currently 99 processes running with 1,310 threads. A process is managed by the operating system and corresponds to a running program and can have many threads. It also occupies memory with code and data and handles for open files, allocated memory. And, of course, the threads themselves need memory. Each thread has its own stack.

My PC’s i7 950 has four cores, or CPUs. Through hyper threading, each of these cores can actually do two threads of execution. It’s like both eyes reading a different book. That’s why the Task Manager shows 8 windows for execution.

taskmanager

Now having more cores is good in theory but there’s a snag illustrated by this picture of CPU usage: It’s not being fully used. That image was taken while running a single-threaded application and, sure enough, Task Manager shows one thread and CPU usage of 13 percent. In other words, it’s only using one out of the eight threads.

CPUUsage

This application that I wrote (14 years ago and recently updated) runs a query against SQLite, fetches a bunch of futures and options, forecasts their possible values up to 10 days ahead, then writes out all the forecast values as huge binary files to disk. Viewing Task Manager for Outlook, by comparison, shows it uses 37 threads.

So why not switch to multithreaded? Well, if I had time it might be worth doing but there are a couple of things to consider.

  1. In Windows, any interactions with the GUI, updating labels, etc., has to be done in the same thread. Other threads cannot update GUIs directly.
  2. I use a DLL for doing several financial calculations, but that DLL may not be thread- safe.

I believe I could partition the three areas reading SQLite, doing the calculations and writing to the binary files into different threads, but as these are done one after another, there may be little or no performance gain. It would need a major redesign to overlap these activities, and of course need a threadsafe DLL. It’s usually better, not to say easier, to design for multithreading than try and retrofit it.

Multi Core Development and Concurrency

For games, the issue of multi-core/multithreading development is significant. While most of the graphics heavy lifting is done by the GPU, games have to find processing time for path finding, object tracking (bullets, etc.), opponent AI, handling network traffic in multiplayer games, loading resources from disk and so on.

C++ being the main language of game development, it’s no coincidence that the recent C++ 11 release has enhanced concurrency, that being the name for doing computations at the same time, and covers both multithreading and multiple cores.

Original C++ didn’t understand the concept of threads and it was platform-specific, e.g., Windows API, which meant it wasn’t very portable. Then came POSIX threads, so people got used to writing software with threads, but getting better performance was never easy.

In C++ 11, the memory model is thread-aware and the Standard Thread Library makes life a lot easier. This has been designed so you don’t need to use low level threading without losing efficiency. However, you can still go to a lower level should you wish with atomic operations using std::atomic<>. Variables declared this way can only be accessed atomically. If one thread reads a 4-byte int that is non-atomically updated, there’s a chance that it’ll read a half updated value. Not good.

There’s a lot more to C++ concurrency. If this is something you wish to know more about, I recommend the Anthony Williams book C++ Concurrency in Action: Practical Multithreading.

Comments

  1. Pingback: This Is What Studios Look for in Game Developers - Dice News

Post a Comment

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>