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?
The pthread_setaffinity_np() function sets the CPU affinity mask of the thread thread to the CPU set pointed to by cpuset. If the call is successful, and the thread is not currently running on one of the CPUs in cpuset, then it is migrated to one of those CPUs.
So thread affinity means that the thread, in this case the UI thread that instantiates an object is the only thread that can access its members. So for example, dependency object in WPF has thread affinity.
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
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With