From e74955b1614b19e594797d859502e4808453a884 Mon Sep 17 00:00:00 2001 From: Markus Ewald Date: Tue, 15 Sep 2009 21:17:34 +0000 Subject: [PATCH] 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 --- Source/AffineThreadPool.cs | 56 +++++++++++++++++++++++++++++++------- 1 file changed, 46 insertions(+), 10 deletions(-) diff --git a/Source/AffineThreadPool.cs b/Source/AffineThreadPool.cs index d169f75..f3ba968 100644 --- a/Source/AffineThreadPool.cs +++ b/Source/AffineThreadPool.cs @@ -22,6 +22,7 @@ using System; using System.Threading; using System.Collections.Generic; using System.Diagnostics; +using System.Runtime.InteropServices; namespace Nuclex.Support { @@ -94,7 +95,12 @@ namespace Nuclex.Support { // We can only use these hardware thread indices on the XBox 360 #if XBOX360 - XboxHardwareThreads = new Queue(new int[] { 5, 4, 3, 1 }); + hardwareThreads = new Queue(new int[] { 5, 4, 3, 1 }); +#else + hardwareThreads = new Queue(CpuCores); + for(int core = CpuCores; core >= 1; --core) { + hardwareThreads.Enqueue(core); + } #endif // Create all of the worker threads @@ -146,7 +152,7 @@ namespace Nuclex.Support { workAvailable.Set(); } - + /// Empties the work queue of any queued work items public static void EmptyQueue() { lock(userWorkItems) { @@ -194,15 +200,27 @@ namespace Nuclex.Support { /// A thread worker function that processes items from the work queue private static void ProcessQueuedItems() { + + int hardwareThreadIndex; + lock(hardwareThreads) { + hardwareThreadIndex = hardwareThreads.Dequeue(); + } + #if XBOX360 // MSDN states that SetProcessorAffinity() should be called from the thread // whose affinity is being changed. - int hardwareThreadIndex; - lock(XboxHardwareThreads) { - hardwareThreadIndex = XboxHardwareThreads.Dequeue(); - } 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 + // Keep processing tasks indefinitely for(; ; ) { @@ -228,6 +246,21 @@ namespace Nuclex.Support { } } + /// Retrieves the ProcessThread for the calling thread + /// The ProcessThread for the calling thread + 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; + } + /// Obtains the next work item from the queue /// The next work item in the queue /// @@ -270,10 +303,13 @@ namespace Nuclex.Support { /// Delegate used to handle assertion checks in the code public static AssertionDelegate AssertionHandler = DefaultAssertionHandler; -#if XBOX360 - /// XNA games on the XBox 360 can use only 4 of 6 hardware threads - private static Queue XboxHardwareThreads; -#endif + /// Retrieves the calling thread's thread id + /// The thread is of the calling thread + [DllImport("kernel32.dll")] + private static extern int GetCurrentThreadId(); + + /// Available hardware threads the thread pool threads pick from + private static Queue hardwareThreads; /// Queue of all the callbacks waiting to be executed. private static Queue userWorkItems; ///