Windows下绑定线程到指定的CPU核心

windows,cpu · 浏览次数 : 16

小编点评

**SetThreadAffinityMask和SetProcessAffinityMask 函数概述** **SetThreadAffinityMask 函数** * 函数名:`SetThreadAffinityMask` * 参数: * `hThread`:指向要设置处理器关联的线程句柄。 * `dwThreadAffinityMask`:处理器的关联掩码。 * 返回值: * 无值 **SetProcessAffinityMask 函数** * 函数名:`SetProcessAffinityMask` * 参数: * `hProcess`:指向要设置处理器关联的进程句柄。 * `dwProcessAffinityMask`:处理器的关联掩码。 * 返回值: * 无值 **CPU核心关联** * `SetThreadAffinityMask` 和 `SetProcessAffinityMask` 函数通过指定 `hThread` 或 `hProcess` 变量将线程或进程关联到特定的 CPU核心。 * 关联的 CPU核心与内核中的逻辑核心有关,而不是物理核心。 * 设置 CPU核心时,需要考虑设备 CPU核心数,并使用 `SetThreadGroupAffinity` 或 `SetProcessAffinityMask` 函数为更清晰的表达其含义。 **性能提升** * 通过绑定线程或进程到特定的 CPU核心,可以减少线程在不同处理器之间的切换开销。 * 避免缓存抖动,确保线程始终在同一个处理器上运行。 * 在实时系统或并发控制场景中,确保线程在特定的处理器上执行,以满足调度需求。 **注意事项** * `SetThreadAffinityMask` 和 `SetProcessAffinityMask` 函数不是独占 CPU核心,如果关联的 CPU核心本身负载就很高,这时候程序执行效率反而会降低。 * 关联 CPU核心时,需要考虑设备 CPU核心数,并使用 `SetThreadGroupAffinity` 或 `SetProcessAffinityMask` 函数为更清晰的表达其含义。

正文

在某些场景下,需要把程序绑定到指定CPU核心提高执行效率。通过微软官方文档查询到Windows提供了两个Win32函数:SetThreadAffinityMaskSetProcessAffinityMask 为指定线程和进程设置处理器关联掩码。通俗的讲就是在指定的CPU核心上执行线程或者进程。

这里的CPU核心指的是逻辑核心,而非物理核心。

SetThreadAffinityMask

SetThreadAffinityMask函数定义

SetThreadAffinityMask的定义如下:

DWORD_PTR SetThreadAffinityMask(
  [in] HANDLE    hThread,
  [in] DWORD_PTR dwThreadAffinityMask
);

从函数的定义看需要传递两个参数:

  • hThread:指向要设置处理器关联的线程句柄。如果是想设置当前线程的关联掩码,可以使用 GetCurrentThread() 函数获取句柄。
  • dwThreadAffinityMask:处理器的关联掩码。是一个DWORD_PTR类型的值,长度共8个字节(64bit),每一bit代表一个cpu核。

如果需要支持超过64核的CPU时,则需要使用SetThreadGroupAffinity函数

为了更清晰的表达dwThreadAffinityMask的含义,下边用二进制数表示该值。比如,需要把线程绑定到
第0个核:则dwThreadAffinityMask=0B_0001;(0x01)
第1个核:则dwThreadAffinityMask=0B_0010;(0x02)
第2个核:则dwThreadAffinityMask=0B_0100;(0x04)
第3个核:则dwThreadAffinityMask=0B_1000;(0x08)
……
如果要绑定到多个cpu核心,比如绑定到第1和2个cpu核时,dwThreadAffinityMask=0B_0110,对应的十六进制数也就是0x06。

调用示例

首先引入Win32API

[DllImport("kernel32.dll")]
static extern UIntPtr SetThreadAffinityMask(IntPtr hThread, UIntPtr dwThreadAffinityMask);

[DllImport("kernel32.dll")]
static extern IntPtr GetCurrentThread();

由于dwThreadAffinityMask的值是按照$2^n$的指数递增,与通常习惯指定第n个核心不符,并且不同的设备CPU核心数不一样,指定CPU核心时可能超出CPU核心数量,因此可以对指定CPU核心做个简单的处理:

static ulong SetCpuID(int lpIdx)
{
    ulong cpuLogicalProcessorId = 0;
    if (lpIdx < 0 || lpIdx >= System.Environment.ProcessorCount)
    {
        lpIdx = 0;
    }
    //通过移位运算转换lgidx->dwThreadAffinityMask:0->1,1->2,2->4,3->8,……
    cpuLogicalProcessorId |= 1UL << lpIdx;
    return cpuLogicalProcessorId;
}

接下来就可以进行测试了

ulong LpId = SetCpuID((int)lpIdx);
SetThreadAffinityMask(GetCurrentThread(), new UIntPtr(LpId));

Stopwatch stopwatch = new Stopwatch();
stopwatch.Start();
for (int i = 0; i < 1000000; i++)
{
    for (int j = 0; j < 1000000; j++)
    {
        int _data = j;
    }
}
stopwatch.Stop();
Console.WriteLine("运行时间: " + stopwatch.ElapsedMilliseconds.ToString());

效果如图如下:
image

SetProcessAffinityMask

SetProcessAffinityMask与SetThreadAffinityMask非常相似,不同的是其作用于整个进程,可以决定进程内的所有线程共同运行在指定的处理器上。
函数定义如下:

BOOL SetProcessAffinityMask(
  [in] HANDLE    hProcess,
  [in] DWORD_PTR dwProcessAffinityMask
);

和SetThreadAffinityMask一样,也是需要传递两个参数,只不过第一个参数传递的是线程的句柄。

小结

在某些场景可以通过SetThreadAffinityMaskSetProcessAffinityMask 提高程序执行效率,主要是基于以下几个原因:

  • 提高性能:通过将线程绑定到特定的处理器,可以减少线程在不同处理器之间的切换开销,尤其是在多核系统中,有助于提升程序的执行效率。
  • 避免缓存抖动:确保线程始终在同一个处理器上运行,可以减少缓存未命中,因为相关的数据更可能保留在该处理器的高速缓存中。
  • 实时系统和并发控制:在需要严格控制线程执行位置的场景下,比如实时系统或者某些并发控制策略中,通过设定处理器关联可以满足特定的调度需求。
    需要注意的是,SetThreadAffinityMask和SetProcessAffinityMask并不是独占CPU核心,如果关联的CPU核心本身负载就很高,这个时候程序执行效率反而会降低。

与Windows下绑定线程到指定的CPU核心相似的内容:

Windows下绑定线程到指定的CPU核心

在某些场景下,需要把程序绑定到指定CPU核心提高执行效率。通过微软官方文档查询到Windows提供了两个Win32函数:SetThreadAffinityMask和SetProcessAffinityMask 为指定线程和进程设置处理器关联掩码。通俗的讲就是在指定的CPU核心上执行线程或者进程。 这

WPF/C#:数据绑定到方法

在WPF Samples中有一个关于数据绑定到方法的Demo,该Demo结构如下: 运行效果如下所示: 来看看是如何实现的。 先来看下MainWindow.xaml中的内容:

WPF控件:密码框绑定MVVM

以下是一种使用 MVVM 模式的方法: 首先,在 ViewModel 中添加一个属性来保存密码,我们可以使用 SecureString 类型。 // 密码变量 private SecureString _password; // 密码属性,用于获取和设置密码 public SecureString

14.1 Socket 套接字编程入门

Winsock是Windows操作系统上的套接字API,用于在网络上进行数据通信。套接字通信是一种允许应用程序在计算机网络上进行实时数据交换的技术。通过使用Windows提供的API,应用程序可以创建一个套接字来进行数据通信。这个套接字可以绑定到一个端口,以允许其他应用程序连接它。另外,Winsoc...

WPF开源轻便、快速的桌面启动器

前言 今天大姚给大家分享一款WPF开源、简单、轻便、快速的桌面启动器(支持多主题、多语言:简体中文、繁体中文、英文等):CurvaLauncher。 WPF介绍 WPF 是一个强大的桌面应用程序框架,用于构建具有丰富用户界面的 Windows 应用。它提供了灵活的布局、数据绑定、样式和模板、动画效果

windows下使用dockerdesktop进行部署

Docker部署springboot项目 环境准备 要在windows上使用docker需要确认系统的需求 需要启用虚拟化支持的CPU 启用适用于windows的Linux子系统功能 保证足够的内存 下载dockerdesktop 下载后会提示安装对应的环境 坑点 安装过程中需要安装wsl环境,会遇

Windows 下自动预约申购 i茅台

今天分享一个自动预约抢茅子的工具! 前期准备工作: 1.需安装:.Net6 依赖 (根据操作系统选择 x64 或 x86 版本进行下载。) 安装软件 1.软件下来下来之后,解压并进入软件目录,我们双击启动程序 软件界面比较简洁,首页里有点击展开菜单的快捷方式 首先我们先进入【预约项目】菜单界面,先刷

[转帖]Rust在windows下安装以后cargo build Error: linker `link.exe` not found

D:\rust\runoob-greeting\greeting>cargo build error: linker `link.exe` not found | = note: 系统找不到指定的文件。 (os error 2) note: the msvc targets depend on th

【冷启动#1】实用的MySQL基础

简单安装一下MySQL Windows下(5.7.x) 本体安装 1、首先先下载安装包,名字如下: mysql-5.7.19-winx64.zip 2、配置环境变量,将解压之后的bin目录添加一下 3、在解压目录下创建my.ini文件,内容如下: [ client ] port=3306 defau

[转帖]Certutil工具(Windows命令行下载常用)

工具介绍 certutil是windows下一款下载文件的工具,自从WindowsServer2003就自带,但是在Server 2003使用会有问题,也就是说,以下命令是在Win7及其以后的机器中使用。其功能可校验文件MD5,SHA1,SHA256,下载恶意文件和免杀 Certutil Certu