The AffineThreadPool class now also tries to create CPU-affine threads on the full .NET framework (which uses P/Invoke and tries to lock a managed thread to a system thread, probably needs some work for Mono)

git-svn-id: file:///srv/devel/repo-conversion/nusu@174 d2e56fa2-650e-0410-a79f-9358c0239efd
This commit is contained in:
Markus Ewald 2009-09-15 21:17:34 +00:00
parent 05e4aebaac
commit e74955b161

View File

@ -22,6 +22,7 @@ using System;
using System.Threading; using System.Threading;
using System.Collections.Generic; using System.Collections.Generic;
using System.Diagnostics; using System.Diagnostics;
using System.Runtime.InteropServices;
namespace Nuclex.Support { namespace Nuclex.Support {
@ -94,7 +95,12 @@ namespace Nuclex.Support {
// We can only use these hardware thread indices on the XBox 360 // We can only use these hardware thread indices on the XBox 360
#if XBOX360 #if XBOX360
XboxHardwareThreads = new Queue<int>(new int[] { 5, 4, 3, 1 }); hardwareThreads = new Queue<int>(new int[] { 5, 4, 3, 1 });
#else
hardwareThreads = new Queue<int>(CpuCores);
for(int core = CpuCores; core >= 1; --core) {
hardwareThreads.Enqueue(core);
}
#endif #endif
// Create all of the worker threads // Create all of the worker threads
@ -146,7 +152,7 @@ namespace Nuclex.Support {
workAvailable.Set(); workAvailable.Set();
} }
/// <summary>Empties the work queue of any queued work items</summary> /// <summary>Empties the work queue of any queued work items</summary>
public static void EmptyQueue() { public static void EmptyQueue() {
lock(userWorkItems) { lock(userWorkItems) {
@ -194,15 +200,27 @@ namespace Nuclex.Support {
/// <summary>A thread worker function that processes items from the work queue</summary> /// <summary>A thread worker function that processes items from the work queue</summary>
private static void ProcessQueuedItems() { private static void ProcessQueuedItems() {
int hardwareThreadIndex;
lock(hardwareThreads) {
hardwareThreadIndex = hardwareThreads.Dequeue();
}
#if XBOX360 #if XBOX360
// MSDN states that SetProcessorAffinity() should be called from the thread // MSDN states that SetProcessorAffinity() should be called from the thread
// whose affinity is being changed. // whose affinity is being changed.
int hardwareThreadIndex;
lock(XboxHardwareThreads) {
hardwareThreadIndex = XboxHardwareThreads.Dequeue();
}
Thread.CurrentThread.SetProcessorAffinity(new int[] { hardwareThreadIndex }); Thread.CurrentThread.SetProcessorAffinity(new int[] { hardwareThreadIndex });
#else
// Prevent this managed thread from impersonating another system thread.
// Threads in .NET can take
Thread.BeginThreadAffinity();
ProcessThread thread = getCurrentProcessThread();
if(thread != null) {
thread.IdealProcessor = hardwareThreadIndex;
}
#endif #endif
// Keep processing tasks indefinitely // Keep processing tasks indefinitely
for(; ; ) { for(; ; ) {
@ -228,6 +246,21 @@ namespace Nuclex.Support {
} }
} }
/// <summary>Retrieves the ProcessThread for the calling thread</summary>
/// <returns>The ProcessThread for the calling thread</returns>
private static ProcessThread getCurrentProcessThread() {
int threadId = GetCurrentThreadId();
ProcessThreadCollection threads = Process.GetCurrentProcess().Threads;
for(int index = 0; index < threads.Count; ++index) {
if(threads[index].Id == threadId) {
return threads[index];
}
}
return null;
}
/// <summary>Obtains the next work item from the queue</summary> /// <summary>Obtains the next work item from the queue</summary>
/// <returns>The next work item in the queue</returns> /// <returns>The next work item in the queue</returns>
/// <remarks> /// <remarks>
@ -270,10 +303,13 @@ namespace Nuclex.Support {
/// <summary>Delegate used to handle assertion checks in the code</summary> /// <summary>Delegate used to handle assertion checks in the code</summary>
public static AssertionDelegate AssertionHandler = DefaultAssertionHandler; public static AssertionDelegate AssertionHandler = DefaultAssertionHandler;
#if XBOX360 /// <summary>Retrieves the calling thread's thread id</summary>
/// <summary>XNA games on the XBox 360 can use only 4 of 6 hardware threads</summary> /// <returns>The thread is of the calling thread</returns>
private static Queue<int> XboxHardwareThreads; [DllImport("kernel32.dll")]
#endif private static extern int GetCurrentThreadId();
/// <summary>Available hardware threads the thread pool threads pick from</summary>
private static Queue<int> hardwareThreads;
/// <summary>Queue of all the callbacks waiting to be executed.</summary> /// <summary>Queue of all the callbacks waiting to be executed.</summary>
private static Queue<UserWorkItem> userWorkItems; private static Queue<UserWorkItem> userWorkItems;
/// <summary> /// <summary>