33

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?

Theodor Zoulias
  • 34,835
  • 7
  • 69
  • 104
mita
  • 331
  • 1
  • 3
  • 3

5 Answers5

51

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 = 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: ProcessThread.ProcessorAffinity Property

aepot
  • 4,558
  • 2
  • 12
  • 24
Phillip
  • 832
  • 7
  • 10
  • 3
    Q: "Can we set two thread or two task to execute with different processor affinity in C# Application?" Notice that the OP asks for different _threads_ in the same _process_. So the question is not about _process_, but _thread_ affinity. – Andras Vass Jan 07 '11 at 11:06
  • There is `Thread.SetProcessorAffinity()` but it only applies to XNA for the Xbox 360. There is no OOTB solution in vanilla .NET, as far as I know. – Andras Vass Jan 07 '11 at 11:11
  • @andras: Good point, I guess I missed the mark a bit. There is a way to do this for threads too, and I edited my example accordingly. Thanks! – Phillip Jan 12 '11 at 00:41
  • 1
    You are welcome. ;) It could be made even more useful if we could get the `ProcessThread` of the current `Thread` so that we could use this on the current thread and then get a nice `using()` construct to revert to the original affinity at the end of the block. That would be great. ;) – Andras Vass Jan 12 '11 at 01:21
  • also i've found this code in internet that probably can be used https://code.google.com/p/disruptor-net/source/browse/trunk/Source/Disruptor/Affinity/ProcessorAffinity.cs?r=128 – Oleg Vazhnev May 20 '13 at 08:08
6

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

ph3rin
  • 4,426
  • 1
  • 18
  • 42
  • example is wrong, `process.Threads[i + offset].ProcessorAffinity = (IntPtr)(1L << 1);` sets the processor affinity to processor 1 only – Not Important Feb 05 '20 at 10:48
  • @FabioAngela *But now we are making a test, so let's bind all the threads to the second processor.* I don't see how my example contradicts the description. – ph3rin Feb 05 '20 at 16:02
  • my bad, commented code above reports i and not 1 so it's fine (read both as 1 at first) – Not Important Feb 05 '20 at 21:39
3
Process.GetCurrentProcess().ProcessorAffinity = (System.IntPtr)2; 
Amey Vartak
  • 309
  • 2
  • 5
  • Although this is answer to different question, it worked for me. Thanks. – Jiří Herník Feb 08 '20 at 16:58
  • 2
    This will change the affinity of whole application (process) effectively assigning same affinity to all threads of this app. OP asked about changing affinity of 2 threads within same app. – Dia Sheikh Jun 26 '20 at 19:52
2

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.

Andrey
  • 59,039
  • 12
  • 119
  • 163
0

The following example from MSDN shows how to set the ProcessorAffinity property for an instance of Notepad to the first processor.

using System;
using System.Diagnostics;

namespace ProcessThreadIdealProcessor
{
    class Program
    {
     static void Main(string[] args)
        {
        // Make sure there is an instance of notepad running.
        Process[] notepads = Process.GetProcessesByName("notepad");
        if (notepads.Length == 0)
            Process.Start("notepad");
            ProcessThreadCollection threads;
            //Process[] notepads; 
            // Retrieve the Notepad processes.
            notepads = Process.GetProcessesByName("Notepad");
            // Get the ProcessThread collection for the first instance
            threads = notepads[0].Threads;
            // Set the properties on the first ProcessThread in the collection
            threads[0].IdealProcessor = 0;
            threads[0].ProcessorAffinity = (IntPtr)1;
        }
    }
}
Ilya Chumakov
  • 23,161
  • 9
  • 86
  • 114
  • 3
    Copy and pasted from https://msdn.microsoft.com/en-us/library/system.diagnostics.processthread.processoraffinity.aspx. Source should be referenced... – Marc Oct 26 '15 at 10:04