views:

583

answers:

3

Can we set two thread or two task to execute with different processor affinity in C# Application?

I have read about SetThreadAffinityMask but there is no example to have that used..

or Is there any way TPL(Task Parallel Libray) executes two thread/Task in with high priority to use 100% cpu ?

A: 

Did you have a look at

Spike Your CPU’s Processor in .Net

astander
A: 

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
+4  A: 

You can use the below ProcessorAffinity.BeginAffinity() to set the processor affinity.

The following sets the affinity to the first CPU (#0):

using (ProcessorAffinity.BeginAffinity(0))
{
    Console.WriteLine("Running on CPU #{0}", NtGetCurrentProcessorNumber());
}

Passing multiple logical CPU identifiers:

using (ProcessorAffinity.BeginAffinity(0,1))
{
    Console.WriteLine("Running on CPU #{0}", NtGetCurrentProcessorNumber());
}

There is also SetThreadAffinity() in there if you don't want using semantics.

Note: NtGetCurrentProcessorNumber() is there only for the sample above. I know it is obsolete. Its P/Invoke signature is:

[DllImport("ntdll.dll", CharSet = CharSet.Auto)]
public static extern uint NtGetCurrentProcessorNumber();

The actual code that you need (sorry for the line breaks, I've pasted it from my helper classes):

/// <summary>
/// Gets and sets the processor affinity of the current thread.
/// </summary>
public static class ProcessorAffinity
{
    static class Win32Native
    {
        //GetCurrentThread() returns only a pseudo handle. No need for a SafeHandle here.
        [DllImport("kernel32.dll")]
        public static extern IntPtr GetCurrentThread();

        [HostProtectionAttribute(SelfAffectingThreading = true)]
        [DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
        public static extern UIntPtr SetThreadAffinityMask(IntPtr handle, UIntPtr mask);

    }

    public struct ProcessorAffinityHelper : IDisposable
    {
        UIntPtr lastaffinity;

        internal ProcessorAffinityHelper(UIntPtr lastaffinity)
        {
            this.lastaffinity = lastaffinity;
        }

        #region IDisposable Members

        public void Dispose()
        {
            if (lastaffinity != UIntPtr.Zero)
            {
                Win32Native.SetThreadAffinityMask(Win32Native.GetCurrentThread(), lastaffinity);
                lastaffinity = UIntPtr.Zero;
            }
        }

        #endregion
    }

    static ulong maskfromids(params int[] ids)
    {
        ulong mask = 0;
        foreach (int id in ids)
        {
            if (id < 0 || id >= Environment.ProcessorCount)
                throw new ArgumentOutOfRangeException("CPUId", id.ToString());
            mask |= 1UL << id;
        }
        return mask;
    }

    /// <summary>
    /// Sets a processor affinity mask for the current thread.
    /// </summary>
    /// <param name="mask">A thread affinity mask where each bit set to 1 specifies a logical processor on which this thread is allowed to run. 
    /// <remarks>Note: a thread cannot specify a broader set of CPUs than those specified in the process affinity mask.</remarks> 
    /// </param>
    /// <returns>The previous affinity mask for the current thread.</returns>
    public static UIntPtr SetThreadAffinityMask(UIntPtr mask)
    {
        UIntPtr lastaffinity = Win32Native.SetThreadAffinityMask(Win32Native.GetCurrentThread(), mask);
        if (lastaffinity == UIntPtr.Zero)
            throw new Win32Exception(Marshal.GetLastWin32Error());
        return lastaffinity;
    }

    /// <summary>
    /// Sets the logical CPUs that the current thread is allowed to execute on.
    /// </summary>
    /// <param name="CPUIds">One or more logical processor identifier(s) the current thread is allowed to run on.<remarks>Note: numbering starts from 0.</remarks></param>
    /// <returns>The previous affinity mask for the current thread.</returns>
    public static UIntPtr SetThreadAffinity(params int[] CPUIds)
    {
        return SetThreadAffinityMask(((UIntPtr)maskfromids(CPUIds)));
    }

    /// <summary>
    /// Restrict a code block to run on the specified logical CPUs in conjuction with 
    /// the <code>using</code> statement.
    /// </summary>
    /// <param name="CPUIds">One or more logical processor identifier(s) the current thread is allowed to run on.<remarks>Note: numbering starts from 0.</remarks></param>
    /// <returns>A helper structure that will reset the affinity when its Dispose() method is called at the end of the using block.</returns>
    public static ProcessorAffinityHelper BeginAffinity(params int[] CPUIds)
    {
        return new ProcessorAffinityHelper(SetThreadAffinityMask(((UIntPtr)maskfromids(CPUIds))));
    }

}
andras