OMG, Multi-Threading Is Easier Than Networking: White Paper
OMG, Multi-Threading Is Easier Than Networking: White Paper
OMG, Multi-Threading Is Easier Than Networking: White Paper
Intel® Threading
OMG, Multi-Threading is
Analysis Tools
Multi-Core Simulation
Easier Than Networking
by Orion Granatir
How threading is easy and similar to network code
Prior to working at Intel, I worked on PlayStation* 3 games at Insomniac Games. Most of the
work I did at Insomniac dealt with multiplayer network code. When I came to Intel, I was able
to focus on threading, eventually realizing that threading and network programming are
similar in several ways.
features, an application needs to fully utilize the CPU—and that • A thread is a series of instructions executed to complete a task.
means threading! • Each process can have multiple threads. Threads share the memory
and resources within a process.
Imagine you want to update the artificial intelligence (AI) for a group
• Just like clients, threads can work independently.
of monsters in your game. If you have only one core, all of those
Here is a process with one thread:
monsters will need to be processed in order. However, if you have
multiple cores, you can process several monsters at the same time.
More cores, and therefore more threads, means you can have more
monsters in your game. Huzzah!
2
White Paper: OMG, Multi-Threading is Easier Than Networking
Okay, let’s see some code. This example creates four threads: one main
thread and three threads that run the PrintLetter function.
Graphics, AI, and UI can all be running on separate threads. They can all
work together through shared resources (for example, main memory).
3
White Paper: OMG, Multi-Threading is Easier Than Networking
Say everyone needs a shovel to complete a quest, but there is Imagine you have three threads that all want to enter a critical section.
only one shovel.
Only one thread can enter the critical section; the other two have to
If a player wants to use the shovel, it must first become the authority sleep. When a thread sleeps, its execution is paused and the OS will
of the shovel. It must agree with all the clients or the server that it has run some other thread.
the right to use the shovel.
Once the thread in the critical section exits, another thread is woken
While this client is using the shovel, all other clients must wait for up and allowed to enter the critical section.
their turn. If multiple clients all want the shovel at the same time, a
mechanism needs to ensure that only one client can access the
shovel at a time.
4
White Paper: OMG, Multi-Threading is Easier Than Networking
During the time that a thread holds the mutex, all other threads
waiting on the mutex sleep. This behavior is very similar to that of a
critical section.
Once a thread has finished using the shared resource, it releases the
mutex. Another thread can then wake up and grab the mutex.
This code creates multiple threads that all print the value of the global
variable count. Since multiple threads want to access count, all access
to this variable is protected by a global critical section. Without the
critical section, multiple threads will try to use count at the same time
causing repeated numbers to print out.
Mutexs and Semaphores A semaphore is a mutex that multiple threads can access. It’s like
having multiple tokens.
A mutex works like a critical section. You can think of a mutex as a
token that must be grabbed before execution can continue. Here is an
example of three threads that all want access to a shared resource.
Each of the three threads tries to grab the mutex, but only one thread
will be successful.
5
White Paper: OMG, Multi-Threading is Easier Than Networking
Events
Events are a way of signaling one thread from another, allowing one
thread to wait or sleep until it’s signaled by another thread.
This example shows two threads using an event: the thread on the
left is producing data, and the one on the right is consuming data.
Once the consuming thread has woken up, it starts doing work. The
assumption is that the producing thread will no longer touch the data.
6
White Paper: OMG, Multi-Threading is Easier Than Networking
This code creates a thread that just waits for the event to trigger
(to be set). The main thread puts some data in the global buffer and
sets the event. Once the event is set, the second thread wakes up
and prints the contents of the buffer.
Atomic Operations
Atomic operations are guaranteed to be “thread safe” because they
are atomic (that is, they happen without interrupts). Here is an
example with three threads that all want to add 1 to a shared variable.
Let’s say all threads run at the same time and see that the shared
value is 5. Now each thread adds 1 and stores the result.
7
White Paper: OMG, Multi-Threading is Easier Than Networking
Deadlock
A deadlock happens when two or more threads are waiting on
resources that are dependent on each other. Here is an example in
which two threads want to do something that requires two mutexes.
This situation is bad; nothing can happen because neither thread has
both mutexes. Worse yet, they will sleep waiting for each other and
never wake up.
Race Conditions
A race condition can happen if the result of the threads’ work is
incorrectly dependent on the sequence of execution. In this example
three threads are each writing a unique character to a shared buffer.
If the threads happen to run in the correct order, they will write ‘CAT’
over and over again.
If one thread gets Mutex0 and the other one gets Mutex1, both don’t
have the required mutex to continue.
8
White Paper: OMG, Multi-Threading is Easier Than Networking
Multi-Thread This!
If you have gotten this far, hopefully you now have a grasp of
network code and some working knowledge about threading. Now,
let’s combine the two! By using threads an application can process
multiple network packets in parallel and decrease process latency.
This game loop does two things: it updates the frame (UpdateFrame)
If you clearly define all the interactions between threads, it’s not too and processes network data (UpdateNetwork). Let’s create some
difficult to avoid deadlocks and race conditions. Intel® Thread Checker threads to process network data.
will help analyze your code and determine locations that might have
one of these pitfalls.
And it’s still easier than finding dup bugs or lag issues in games.
9
White Paper: OMG, Multi-Threading is Easier Than Networking
The threads are simple enough: they run in a loop sleeping until
the NetworkUpdateEvent event is triggered. Once the event is set, the
threads all call UpdateNetwork. This function calls GetNetworkMessages
to read network messages and ProcessNetworkMessage to process
the packet. These two functions must be thread-safe because multiple
threads will call them and access the shared data.
We can improve this example by adding better load balancing. For exam-
ple, instead of just having the main thread signal NetworkUpdateEvent
and wait, it could call UpdateNetwork and help out. Furthermore, the
three created threads could help out with UpdateFrame.
For simplicity’s sake, one step was omitted from this example: the
Now let’s look at NetworkThread. main thread needs to wait for the helper threads to finish processing
the network data before it continues and resets the event.
Conclusion
Threading can be a challenge, but using threads is necessary
to unlock the power of the CPU and maximize an application’s
performance. Current trends indicate that CPU manufacturers will
continue to add more and more cores. Hopefully you now feel more
comfortable with threading, so give it a try in your own application.
Threading FTW!
©
Copyright 2009 Intel Corporation. All rights reserved. Intel and the Intel logo are trademarks of Intel Corporation in the U.S.
and other countries.
*Other names and brands may be claimed as the property of others.
Printed in USA 0209/WD/CS/PDF Please Recycle