Search

Advertising

Home Downloads Components

Components

Folder Path: \ Components \

File: Core-Affine Thread Pool for XNA

file.png
Uploaded:
September.17.09
Modified:
September.17.09
File Size:
9 KB
Downloads:
670
Version
1.0

A custom thread pool which creates one thread for each available CPU core. This avoids bottlenecks on the XBox 360, where all threads (including the .NET ThreadPool) run on core 1 unless explicitly assigned to another core. On Windows, it exposes similar behavior by suggesting a core to the OS instead of using hard affinity.

Details

If you try to speed up mass calculations using threads on the XBox 360, you might discover that all your threads are running on core 1. Even the entire ThreadPool seems to use only one hardware thread, even though the XBox 360 supposedly has 6 of them (of which XNA developers can use 4).

This is so because threads need to be assigned to a different hardware thread explicitly. Creating threads is a time-consuming process, so instead of letting each multi-threaded component in my games create its own four threads, I created a clone of the ThreadPool which made use of the additional cores.

Illustration of the XBox 360's six hardware threads

To expose comparable behavior on Windows, one thread is created for each logical CPU (meaning it would create 8 threads on a quad-core CPU with hyper-threading). Instead of using hard affinity, my thread pool will only suggest a core. This allows the thread scheduler to still do its work while not drastically altering the behavior of the AffineThreadPool.

Fixing threads to a CPU core is a bad idea on Windows because you're essentially circumventing the OS' thread scheduler. This can very well lead to worse performance - imagine core 1 is busy doing some OS bookkeeping and you cleverly distribute work across the whole CPU. What happens?

All cores finish their work but the thread that's fixed to core 1 is still waiting. And even though the other cores are free and could take over, the thread scheduler can't help you because you fixed the thread to core 1. See here for another description of the problem: Parallelism and CPU Affinity.

Example

The AffineThreadPool works almost exactly like a trimmed-down version of .NET's ThreadPool class. On the PC, it's marginally slower than the real ThreadPool (even though it's the tightest implementation I could come up with that still works on the XBox 360 - hats off to the ThreadPool developers! .NET 4.0 will make it even faster, by the way.)

// Give the thread pool a task to process in the background
AffineThreadPool.QueueUserWorkItem(
  delegate(object state) {
    Console.WriteLine("Hello World");
  }
);

Unhandled exceptions reaching the AffineThreadPool are ignored by default, but you can trap them and add an assertion or whatever you'd like to do by setting a delegate in the AffineTheadPool class. I would have loved to use AppDomain.UnhandledException, but there's no (clean) way to fire that event from code.

// Use a custom exception handler that brings up an assertion dialog
AffineThreadPool.ExceptionHandler = delegate(Exception exception) {
  Debug.Fail(
    "Unhandled exception in ThreadPool thread",
    exception.ToString()
  );
  throw exception;
};

// Now queue a task that will cause an unhandled exception in a thread
// pool thread to test the custom exception handler.
AffineThreadPool.QueueUserWorkItem(
  delegate(object state) {
    throw new Exception("This is a test!");
  }
);

Features

  • 100% unit test coverage for everything
  • Works on the XBox 360 and PC
  • Should be easy to port to the compact framework
  • Allows easy usage of the XBox 360's cores
  • Comparable behavior across platforms
  • On the PC, suggests core, but doesn't enforce

This class is part of the Nuclex.Support library from the Nuclex Framework. You can find the most recent release of the code on the framework's CodePlex site:
http://nuclexframework.codeplex.com/



Joomla Template by Joomlashack