Multithreading Revisited

Thursday, November 19th, 2009

So I was reading an article by John Siracusa on arstechnica.com about ¬†Snow Leopard recently and he had a great segment about Apple’s new Grand Central Dispatch technology. The idea of GCD is to allow developer’s to easily multithread code without having to do all the work that I had to go through. Before I get into that though let’s cover the basis of what GCD is. First of all GCD is a low level means of handling threads automatically. When developing for a multiprocesser system developers don’t have much knowledge of what the current system state is. Sure I have four cores, but how many are available? Once you let GCD know you want something threaded it can farm out the work for you. No checking for number of processor cores or if hyperthreading is available. Sweet.

Grand Central Dispatch also allows you to multithread in just a few lines of code. John does a great job of explaining it so hit the link above and read up if you want more in depth information on the technology. The short version is that blocks + GCD = multithreading bliss.

So all of this got me thinking about my previous article on multithreading a workload and how I could improve it. One thing that would make sense would be to use a stack instead of splitting my list up into equal parts. A stack is like a pile of paper. You can pull things off the top of the stack and expose the page underneath. So if I passed the same stack to each thread then the threads would peel off the work bit by bit until the stack was gone.

  • Once the stack is empty then the threads will terminate themselves.
  • I could add work to the stack as it is being processed (of course being careful that the threads don’t terminate before I am done collecting work)
  • I don’t have to worry about one subset of work finishing faster than another.

So let’s run a little pseudo code for this framework:

private void Multithread()
{
  Stack<int> stack = new Stack<int>(100); //stack of 100 something
  for (int i = 0; i < 100; i++) { stack.Push(i); } //fill the stack
  Thread[] threads = new Thread[System.Environment.ProcessorCount];

  //Create the threads and pass the same stack to each one
  for (int i = 0; i < threads.Length; i++)
  {
       threads[i] = new Thread(delegate() {
                      DoSomething(stack);
                    });
       threads[i].Start();
  }
<pre style="font: normal normal normal 12px/18px Consolas, Monaco, 'Courier New', Courier, monospace;">   //wait for execution to finish
  foreach (Thread thread in threads) { thread.Join(); }</pre>
}

And our worker function which will terminate once the stack has emptied

private void DoSomething(Stack<int> stack)
{
 while (stack.Count > 0)
 {
    int j = stack.Pop();
    Debug.Print(j.ToString());
 }
 return;
}

Leave a Reply