linux指定cpu运行程序,进程/线程绑定到特定CPU核的linux实现(有代码有实例)
前言
现在计算机上的CPU大多都是多核的,有4核甚至是8核的。但是一个计算机启动之后其进程数是远远多于CPU核数的,因为操作系统会给自动调度这些进程在CPU核上轮流运行。但是对于应用程序或者进程,其性能要求较高时,可能有必要绑定该进程到指定的CPU核来运行,避免调度带来的额外开销。我自己也是因为最近的项目上有需要进程运行在指定的CPU核上的要求,所以了解了一下这项技术,并且将过程和总结记录于此。
CPU亲和性
在学习这项新技术之前,我们先来了解一下什么是CPU亲和性?所谓亲和性,就是把进程在指定的 CPU 上尽量长时间地运行而不被迁移到其他处理器,也称为CPU关联性;再简单的点的描述就将制定的进程或线程绑定到相应的cpu上;在多核运行的机器上,每个CPU本身自己会有缓存,缓存着进程使用的信息,而进程可能会被OS调度到其他CPU上,如此,CPU cache命中率就低了,当绑定CPU后,程序就会一直在指定的cpu跑,不会由操作系统调度到其他CPU上,性能有一定的提高。
预备知识
在编写测试程序之前,我们先来了解一下CPU相关的宏和函数。
1.首先要想使用CPU系列函数及相关的宏,需要声明下面的宏,以告诉编译器启用这些函数
#define _GNU_SOURCE
2.声明一个cpu_set_t,然后用 CPU_ZERO()宏来初始化数据:
cpu_set_t mask;
CPU_ZERO(&mask);
3.再下来就是要指定绑定的CPU核心,用CPU_SET()宏来指定,例如:
CPU_SET(1, &mask);//绑定CPU核心1
4.下面这个函数是进程绑定CPU核心最关键函数,也是实际绑定CPU核的操作。其原型即参数说明如下:
int sched_setaffinity(pid_t pid, size_t cpusetsize, cpu_set_t *mask);
该函数设置进程为pid的这个进程,让它运行在mask所设定的CPU上.如果pid的值为0,则表示指定的是当前进程,使当前进程运行在mask所设定的那些CPU上.第二个参数cpusetsize是mask所指定的数的长度.通常设定为sizeof(cpu_set_t).如果当前pid所指定的进程此时没有运行在mask所指定的任意一个CPU上,则该指定的进程会从其它CPU上迁移到mask的指定的一个CPU上运行。
用法:
sched_setaffinity(0, sizeof(cpu_set_t), &mask);//设置完mask之后,通过该函数完成实际绑定功能
5.补充:通过上面的4步就可以完成进程绑定CPU核心了,即被绑定的进程会一直运行在指定的CPU核上,不会被操作系统调度走。在这里,我们再介绍一下另外两个宏:
void CPU_CLR (int cpu, cpu_set_t *set)
这个宏将 指定的 cpu 从 CPU 集 set 中删除。
int CPU_ISSET (int cpu, const cpu_set_t *set)
检查 cpu 是否是 CPU 集 set 的一员,如果在CPU集中这个宏就返回一个非零值(true),否则就返回零(false)。
还有一个函数其功能是获取当前进程运行在哪一个CPU核:
int sched_getcpu();
测试程序
接下来,我们就用一个测试程序来看一下进程是否被绑定在一个CPU核上。
#define _GNU_SOURCE
#include
#include
#include
#include
int main()
{
cpu_set_t mask;
CPU_ZERO(&mask);
CPU_SET(1, &mask);//把main进程绑定到CPU1
sched_setaffinity(0, sizeof(cpu_set_t), &mask);//实际的绑定函数
printf("cpu = %d\n",sched_getcpu());//打印当前运行的CPU核,看是否绑定成功
int i,j,k;
for(i = 0;i < 40;i++)
{//循环40亿次
printf("i = %d\n",i);
for(j = 0;j < 10000;j++)
{
for(k = 0;k < 10000;k++)
{
if(sched_getcpu() != 1)//如果当前CPU核不是1,说明被操作系统给调度走了,绑定失败!并且打印当前运行的CPU核
{
printf("main process: cpu = %d\n",sched_getcpu());
}
}
}
}
printf("main end\n");
return 0;
}
编译测试程序:g++ cpu.cpp -o cpu
运行程序:./cpu
结果如下:
可以看到,打印的CPU核正是我们绑定的CPU,并且没有打印程序中测试绑定失败的相关log,说明循环了40亿次,main进程一直都在CPU1上运行的。
进阶测试
上面的测试,我们只是做到了被绑定的进程确实运行在了指定的CPU上,但是期间是否有其他进程被操作系统调度进来运行呢?被绑定的进程是否独享指定的CPU呢?现在我们就通过测试程序来测试看看。这里我们还是需要上面刚写的测试程序来辅助测试,这里暂且称上面的程序为测试程序1吧。下面我们要写第二个测试程序,其功能就是fork5个子进程,并且对这5个子进程不做绑定,任由操作系统默认调度,测试程序2如下:
#define _GNU_SOURCE
#include
#include
#include
#include
void run(int c, int n,int cpu) {
int lastcpu = cpu;
// if(c == 0)
// {
// cpu_set_t mask;
// CPU_ZERO(&mask);
// CPU_SET(n, &mask);
// sched_setaffinity(0, sizeof(cpu_set_t), &mask);
// printf("c= %d,cpu = %d\n",c,sched_getcpu());
// }
int i,j,k;
for (i = 0; i != 60; i++) //循环60亿次
{
printf("c = %d,i = %d\n",c,i);
for(j = 0; j != 10000; j++)
{
for(k = 0;k != 10000;k++)
{
if(sched_getcpu() != lastcpu)//如果当前的CPU核和上次的CPU核不一样,说明该进程被调度了,这样只要进程发生了调度我们就可以知道该进程是从CPU的哪个核调度到哪个核
{
printf("c = %d,i = %d,lastcpu = %d, nowcpu = %d\n",c,i,lastcpu,sched_getcpu());
lastcpu = sched_getcpu(); //更新lastcpu的值
}
}
}
}
printf("c = %d ,i = %d, j = %d,is end\n",c,i,j);
}
int main()
{
int i,initcpu;
for (i = 0; i != 5; i++) {//循环5次,产生了5个子进程
int pid = fork();
if (pid == 0) {//fork返回值为0表明是子进程,if判断里面只有子进程会跑
initcpu = sched_getcpu();//获取各个进程被分配到哪个CPU核
printf("i = %d,initcpu = %d\n",i,initcpu);
run(i, i,initcpu);//每一个子进程都会跑run函数
exit(0);
}
}
return 0;
}
好了,现在我们有一个绑定了CPU1的测试程序1,以及任由操作系统调度的测试程序2.
测试方法就是先执行测试程序1,目的是让测试程序1绑定CPU1,然后再运行测试程序2,由于测试程序2中的子进程都是操作系统默认调度的,所以可以看看测试程序1还在运行期间,测试程序2中的进程是否会被调度到CPU1上。
执行结果:
由于运行结果log较多,这里不一一上传,但是我们从上面的结果中可以看到,在测试程序1执行期间,测试程序2中的这些被系统自动调度的进程并没有一个进程被调度到CPU1上,直到程序1执行完了之后测试程序2的进程才被调度到CPU1上。
线程绑定CPU
线程绑定CPU的函数如下:
int pthread_setaffinity_np(pthread_t thread, size_t cpusetsize, const cpu_set_t *cpuset);
绑定线程与进程的过程和方法都类似,这里就不详细介绍了,读者可以在了解了进程绑定之后再亲自尝试一下线程绑定。
总结
经过上面测试程序的测试我们可以得出以下结论:
1.经过sched_setaffinity函数绑定了CPU之后,进程在其运行期间是独享该核心的,其他被操作系统自动调度的进程不会在该CPU核心上运行。
2.只有 在被绑定的进程运行结束之后,该核心就会被释放,供操作系统自动调度。
linux指定cpu运行程序,进程/线程绑定到特定CPU核的linux实现(有代码有实例)相关推荐
- 为什么要把进程/线程绑定到特定cpu核上运行?(cpu core id coreIdx)opdevsdk_sys_bindThreadCoreId()
看海康hikflow_demo代码,在线程处理函数里调用了绑定函数,把这个线程绑定到某个cpu核上,不知为何要这么做? 原因 答1 现在大家使用的基本上都是多核cpu,一般是4核的.平时应用程序在运行 ...
- linux下把进程绑定到特定cpu核上运行
现在大家使用的基本上都是多核cpu,一般是4核的.平时应用程序在运行时都是由操作系统管理的.操作系统对应用进程进行调度,使其在不同的核上轮番运行. 对于普通的应用,操作系统的默认调度机制是没有问题的. ...
- linux上根据运行程序的进程号,查看程序所在的绝对路径。linux查看进程启动的时间
1 linux上根据运行程序的进程号,查看程序所在的绝对路径 1.如下,我想查看python 25_run_train_tripletloss_sknet_8w_offline_c_plus.py 这 ...
- CPU核心数线程数、程序进程线程、并发并行的简单理解
CPU核心数线程数.程序进程线程.并发并行.简单理解和区分 这篇文章是对上述感念的简单理解,想深入研究可以看看<计算机组成原理> CPU的核心数 线程数 当我们买电脑的时候,会看到CPU的 ...
- linux的进程/线程/协程系列3:查看linux内核源码——vim+ctags/find+grep
linux的进程/线程/协程系列3:查看linux内核源码--vim+ctags/find+grep 前言 摘要: 1. 下载linux内核源码 2. 打标签方法:vim+ctags 2.1 安装vi ...
- linux c进程线程的面试问题,linux 多线程面试题_linux进程线程_linux 线程 pthread_create...
你写了一个简单的mandelbrot set程序,也就是说用ps命令行是可以看见多个线程,win32里同一个进程里各个线程之间是共享数据段的,win32的进程管理方式与unix上有着很大区别.adob ...
- 在Red Hat Linux中自动运行程序
在Red Hat Linux中自动运行程序 1.开机启动时自动运行程序 Linux加载后, 它将初始化硬件和设备驱动, 然后运行第一个进程init.init根据配置文件继续引导过程,启动其它进程.通常 ...
- 02 线程简介 多任务 多线程 普通方法调用和多线程 程序.进程.线程 Proces与Thread 核心概念
线程简介 任务,进程,线程,多线程 多任务 多任务处理是指用户可以在同一时间内运行多个应用程序,每个应用程序被称作一个任务 多线程 原来是一条路,慢慢因为车太多了,道路堵塞,效率极低. 为了提高使用的 ...
- Linux命令--定时运行程序(脚本)--方法/实例
原文网址:Linux命令--定时运行程序(脚本)--方法/实例_IT利刃出鞘的博客-CSDN博客 简介 说明 本文介绍Linux如何定时运行程序. 概述 at命令是一次性定时计划任务, ...
最新文章
- 曾经我也迷茫,你还在迷茫吗?写给像我一样的在校计算机专业学生作者:Cat_Lee 来源:博客园 发布时间:2009-05-30 20:25 阅读:1104 次 原文链接 [收藏]
- MySQL5.6 选项和变量整理
- Linux设置Oracle开机自启动
- 社区论坛小程序带订阅功能
- java生成随机十位数_随机10位字符串生成
- ajax实战用法详解
- linux安装界面意思,为linux安装图形化界面
- L1-041 寻找250 (10 分)—团体程序设计天梯赛
- (六)Value Function Approximation-LSPI code (3)
- 16位图xxxxxxxxxxxx
- 【游戏开发实战】Unity实现类似GitHub地球射线的效果(LineRenderer | 贝塞尔曲线)
- VC++即时通+视频会议源码
- 运营小技能:订阅号文章排版教程(添加图片超链接、推文采集、往期推荐)
- 论坛刷访客神器-Header自定义工具
- 用 GNS3 做CCNA网络实验(4)
- 异步和同步数据备份的差别_备份和同步数据的最佳文章
- Keil5使用AC6编译器
- 老闪创业那些事儿(14)——测试老白变身记
- 从数字城市迈向智能城市
- 遥感图像处理:最小噪声分离变换(Minimum Noise Fraction Rotation,MNF Rotation)
热门文章
- mysql workbench 存储过程_MySQL Workbench创建存储过程教程示例
- docker mysql5.7 主从_使用Docker部署MySQL 5.78.0主从集群的方法步骤
- r 64位连接mysql_R与Mysql数据库连接的两种方法
- 常见的通配符_技术干货 | 常见的mysql注入语句
- python读大文件方法_使用Python读取大文件的方法
- java 获取组件大小_java - 如何初始化取决于组件大小的图像抓取? - 堆栈内存溢出...
- mysql 删除表时外键约束_MySQL删除表的时候忽略外键约束的简单实现
- 在chrome里查询修改html代码,我需要在网页中直接编辑CSS?打开Web代码检查器
- linux中用户 机器名,Python 在linux下获得当前工作目录,主机名,用户名,操作系统平台等信息...
- retrofit框架学习(一)----基本用法