Well I have done some basic threading in my job, basic stuff and thought I would try and put the basic threading I have done into an XNA Game Component. I am not saying this is how you should do your threading, my method is certainly not the only way to thread processes either and more than likely not the best. I think though that if you are new to development and you want to thread part of your game then I think this may be of some use to you.
What is a thread?
OK, there are a few links out there that describe what a thread is better than I could, so here are a few links for reference:-
Research Microsoft Andrew D. Birrel (not read this yet, looks v good though)
MSDN (Again, I should read this too...)
This is a simple manager, you can pass methods to it that you want to have processed in a thread of there own. You can have as many threads as you like, BUT, it's probably best to keep your threads down to as few as possible, don't go threading processes because you can.
So, on to the code. The ThreadManager class is derived from (as most my samples) from GameComponent. The threading method I use requires four components, ParameterizedThreadStart if you don't need to pass parameters to your thread start method then you can use ThreadStart; these are how we bind our method to a Thread, Thread this is the actual thread class used to start and stop the thread, ManualResetEvent this class is used to manage the call interval for the thread and the Mutex class which is used to ensure there are no thread clashes. I wanted to be able to add as many threads as I wanted in my ThreadManager so I have put these class instances into Dictionaries. Also in this implementation I wanted to be able to manage how often the thread code was ran and also to be able to kill a thread at will. To do this I added two other dictionaries to hold what threads I want to stop and one for the interval between thread calls.
As you can see in the code snippet above, there are 4 methods that are not native to the GameComponent, AddThread, KillThread, StartThread, ThreadWorker.
Well, guess what this method does...yep, adds a thread to the manager. So each thread needs one of the base thread elements to, I also set the interval and if the thread is stopped. I set the flag to say this thread has been stopped, then call the threads Join method, this stops (blocks) this thread from running until the thread terminates, this won't happen until the threads loop in ThreadWorker exits and is why I set the stop flag for the thread so that it will terminate. You will see in this call I use another class ThreadCodeObj.
This class stores the code to be called in the thread and the index of the thread it is to be used in.
Yep, you got it, kills a running thread. First off the treads mutex calls it's WaitOne method, this method holds this thread up until it's free to do it's work.
Restarts a killed thread. First check if this thread has been stopped, if it has then re initialise the threads elements.
Well this I guess is where it all happens, first we get the index of the thread we are in, then we kick off the threads loop, get the mutex for this thread to tell us when it is safe to call the delegate, then we make sure the gameTime instance is not null and call the delegate. We then get the mutex for this thread to signal that we are done and then check if we need to leave the loop and if not wait for the given interval for this thread index.
So as with most of my samples (I like to think) it's simple to add a method to a thread. First of all set up the ThreadManager and add it to the Game.Components list, now simply call the ThreadManager.AddThread method, passing it the method you want to put in the thread via the ThreadCode delegate along with the interval you want for the thread. I guess most of the threads you will create will have a time span of 0 so they are executed immediately.
You will also notice I have not bothered with affinity (the ability to request the processor the thread will run on) in this sample, this is because on a PC, you wont know how many CPU's your application will be running on so it's probably best left up to the OS to sort it out.
My next post on threading will be for the XBox, it will be almost identical with this source but will have affinity included, we know where we stand with the 360, we know what processors, how many cores and which ones we can put threads on.
The sample code shows this working in a very simplistic manor, I simply add three methods to the thread manager that populate a variable that holds the game time each time it is called. You can kill the thread and then re start them with an interval of 0.
Source solution can be found here.