How can I set processor affinity to a thread or a Task in .NET?
Can we set two threads or two tasks to execute with different processor affinity in a C# application?
I have read about SetThreadAffinityMask
, but have found no example of how that should be used.
Alternatively, is there any way for TPL (Task Parallel Library) to execute two threads/Tasks with high priority to use 100% CPU?
Process
and ProcessThread
objects have a ProcessorAffinity
property of IntPtr
type that can be directly manipulated to read/change affinity for up to 64 processors:
using System.Diagnostics;
...
Process Proc = Process.GetCurrentProcess();
long AffinityMask = (long)Proc.ProcessorAffinity;
AffinityMask &= 0x000F; // use only any of the first 4 available processors
Proc.ProcessorAffinity = (IntPtr)AffinityMask;
ProcessThread Thread = Proc.Threads[0];
AffinityMask = 0x0002; // use only the second processor, despite availability
Thread.ProcessorAffinity = (IntPtr)AffinityMask;
...
You can also use the thread's IdealProcessor
property to allow the scheduler to prefer running the thread on a specified processor (without guarantee).
Yes, it's that easy :)
Reference: MSDN ProcessThread.ProcessorAffinity Property
Actually, .NET Framework and Windows manage the threads pretty well, distributing them evenly on every processor. However, the distribution of threads can be manipulated manually using Process
and ProcessThread
.
using System;
using System.Diagnostics;
using System.Threading;
namespace ThreadTest
{
class Program
{
static void Main(string[] args)
{
//Get the our application's process.
Process process = Process.GetCurrentProcess();
//Get the processor count of our machine.
int cpuCount = Environment.ProcessorCount;
Console.WriteLine("CPU Count : {0}", cpuCount);
//Since the application starts with a few threads, we have to
//record the offset.
int offset = process.Threads.Count;
Thread[] threads = new Thread[cpuCount];
Console.WriteLine(process.Threads.Count);
LogThreadIds(process);
//Create and start a number of threads that equals to
//our processor count.
for (int i = 0; i < cpuCount; ++i)
{
Thread t = new Thread(new ThreadStart(Calculation))
{ IsBackground = true };
t.Start();
}
//Refresh the process information in order to get the newest
//thread list.
process.Refresh();
Console.WriteLine(process.Threads.Count);
LogThreadIds(process);
//Set the affinity of newly created threads.
for (int i = 0; i < cpuCount; ++i)
{
//process.Threads[i + offset].ProcessorAffinity = (IntPtr)(1L << i);
//The code above distributes threads evenly on all processors.
//But now we are making a test, so let's bind all the threads to the
//second processor.
process.Threads[i + offset].ProcessorAffinity = (IntPtr)(1L << 1);
}
Console.ReadLine();
}
static void Calculation()
{
//some extreme loads.
while (true)
{
Random rand = new Random();
double a = rand.NextDouble();
a = Math.Sin(Math.Sin(a));
}
}
static void LogThreadIds(Process proc)
{
//This will log out all the thread id binded to the process.
//It is used to test whether newly added threads are the latest elements
//in the collection.
Console.WriteLine("===Thread Ids===");
for (int i = 0; i < proc.Threads.Count; ++i)
{
Console.WriteLine(proc.Threads[i].Id);
}
Console.WriteLine("===End of Thread Ids===");
}
}
}
Now check the task manager, we can see that that the second processor is taking all the work loads. The task manager window
Actually OS is capable of load balancing your cores/processors but if you want to do it explicitly use mentioned via PInvoke. You pass id of thread (not managed one!) and mask - the bit array of cores.