//==============================================================
// 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);
}
}