//============================================================== // Copyright (C) 2020 Inc. All rights reserved. // //============================================================== // Create by 种道洋 at 2020/7/20 13:44:40. // Version 1.0 // 种道洋 //============================================================== using System; using System.Collections.Generic; using System.ComponentModel; using System.Runtime.InteropServices; using System.Runtime.Versioning; using System.Text; namespace Cdy.Tag { /// /// /// public class ThreadHelper { #region ... Variables ... #endregion ...Variables... #region ... Events ... #endregion ...Events... #region ... Constructor... #endregion ...Constructor... #region ... Properties ... #endregion ...Properties... #region ... Methods ... /// /// CPU 个数 /// /// public static int GetProcessNumbers() { return Environment.ProcessorCount; } /// /// 将当前线程绑定到指定CPU /// /// public static void AssignToCPU(params int[] cpus) { if(RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) { SetThreadAffinityMaskWindows((UIntPtr)MaskFromIds(cpus)); } else if(RuntimeInformation.IsOSPlatform(OSPlatform.Linux)) { SetThreadAffinityMaskLinux(MaskFromIds(cpus)); } else { //to do none; } } /// /// 获取当前线程所在CPU ID /// /// public static uint GetCurrentProcessorNumber() { if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) { return Win32Native.NtGetCurrentProcessorNumber(); } else if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux)) { //ulong re = 0; //LinuxNative.pthread_getaffinity_np(LinuxNative.pthread_self(), ref re); //return (uint)re; } else { //to do none; } return uint.MaxValue; } /// /// Sets a processor affinity mask for the current thread. /// /// /// A thread affinity mask where each bit set to 1 specifies a logical processor on which this thread is allowed to /// run. /// Note: a thread cannot specify a broader set of CPUs than those specified in the process affinity mask. /// /// /// The previous affinity mask for the current thread. /// /// public static UIntPtr SetThreadAffinityMaskWindows(UIntPtr mask) { var threadAffinityMask = Win32Native.SetThreadAffinityMask(Win32Native.GetCurrentThread(), mask); if (threadAffinityMask == UIntPtr.Zero) { throw new Win32Exception(Marshal.GetLastWin32Error()); } return threadAffinityMask; //return SetThreadAffinityMask(Win32Native.GetCurrentThread(), mask); } /// /// /// /// public static void SetThreadAffinityMaskLinux(ulong mask) { LinuxNative.pthread_setaffinity_np(LinuxNative.pthread_self(),8,ref mask); } /// /// Masks from ids. /// /// The ids. /// /// CPUId private static ulong MaskFromIds(IEnumerable ids) { ulong mask = 0; foreach (var id in ids) { if (id < 0 || id >= Environment.ProcessorCount) { throw new ArgumentOutOfRangeException("CPUId", id.ToString()); } mask |= 1UL << id; } return mask; } /// /// Ids from mask. /// /// The mask. /// private static IEnumerable IdsFromMask(ulong mask) { var ids = new List(); var i = 0; while (mask > 0UL) { if ((mask & 1UL) != 0) { ids.Add(i); } mask >>= 1; i++; } return ids; } #endregion ...Methods... #region ... Interfaces ... #endregion ...Interfaces... } public static class LinuxNative { private const string pthread = "libpthread.so.0"; /// /// /// /// /// /// /// [DllImport(pthread, CharSet = CharSet.Auto, SetLastError = true)] public static extern int pthread_setaffinity_np(IntPtr threadHandel, int cpusize,ref UInt64 cpuset); /// /// /// /// /// /// [DllImport(pthread, CharSet = CharSet.Auto, SetLastError = true)] public static extern int pthread_getaffinity_np(IntPtr threadHandel,ref UInt64 cpuset); /// /// /// /// [DllImport(pthread, CharSet = CharSet.Auto, SetLastError = true)] public static extern IntPtr pthread_self(); } /// /// Win32Native Class /// public static class Win32Native { /// /// The kernel32 /// private const string Kernel32 = "kernel32.dll"; /// /// The NTDLL /// private const string Ntdll = "ntdll.dll"; /// /// The psapi /// private const string Psapi = "psapi.dll"; /// /// Enums the processes. /// /// The process ids. /// The size. /// The needed. /// [DllImport(Psapi, CharSet = CharSet.Auto, SetLastError = true)] [ResourceExposure(ResourceScope.Machine)] internal static extern bool EnumProcesses(int[] processIds, int size, out int needed); /// /// Opens the process. /// /// The access. /// if set to true [inherit]. /// The process identifier. /// [DllImport(Kernel32, CharSet = CharSet.Auto, SetLastError = true)] [ResourceExposure(ResourceScope.Machine)] internal static extern IntPtr OpenProcess(int access, bool inherit, int processId); /// /// Sets the thread affinity mask. /// /// The handle. /// The mask. /// [DllImport(Kernel32, CharSet = CharSet.Auto, SetLastError = true)] [ResourceExposure(ResourceScope.Process)] internal static extern IntPtr SetThreadAffinityMask(IntPtr handle, HandleRef mask); /// /// Get current processor number. /// /// [DllImport(Ntdll, CharSet = CharSet.Auto)] internal static extern uint NtGetCurrentProcessorNumber(); /// /// Gets the current thread. GetCurrentThread() returns only a pseudo handle. No need for a SafeHandle here. /// /// [DllImport(Kernel32)] internal static extern IntPtr GetCurrentThread(); /// /// Sets the thread affinity mask. /// /// The handle. /// The mask. /// [DllImport(Kernel32, CharSet = CharSet.Auto, SetLastError = true)] internal static extern UIntPtr SetThreadAffinityMask(IntPtr handle, UIntPtr mask); /// /// Sets the process affinity mask. /// /// The handle. /// The mask. /// [DllImport(Kernel32, CharSet = CharSet.Auto, SetLastError = true)] [ResourceExposure(ResourceScope.Machine)] internal static extern bool SetProcessAffinityMask(IntPtr handle, IntPtr mask); /// /// Gets the process affinity mask. /// /// The handle. /// The process mask. /// The system mask. /// [DllImport(Kernel32, CharSet = CharSet.Auto, SetLastError = true)] [ResourceExposure(ResourceScope.None)] internal static extern bool GetProcessAffinityMask( IntPtr handle, out IntPtr processMask, out IntPtr systemMask); } }