CPU线程和进程绑核
前言
提示:这里可以添加本文要记录的大概内容:
CPU绑定指的是在多核CPU的系统中将进程或线程绑定到指定的CPU核上去执行。在Linux中,我们可以利用CPU affinity属性把进程绑定到一个或多个CPU核上。
CPU Affinity是进程的一个属性,这个属性指明了进程调度器能够把这个进程调度到哪些CPU上。该属性要求进程在某个指定的CPU上尽量长时间地运行而不被迁移到其他处理器。
CPU Affinity分为2种:soft affinity和hard affinity。soft affinity只是一个建议,如果不可避免,调度器还是会把进程调度到其它的CPU上去执行;hard affinity则是调度器必须遵守的规则, 2.6以上版本的Linux内核可以让开发人员可以编程实现hard affinity
一、进程绑核C语言实现
#include <sched.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char *argv[])
{
cpu_set_t set;
int parentCPU, childCPU;
int j;
int cpu_num = -1;
if (argc != 3) {
fprintf(stderr, "Usage: %s parent-cpu child-cpu\n", argv[0]);
exit(EXIT_FAILURE);
}
parentCPU = atoi(argv[1]);
childCPU = atoi(argv[2]);
CPU_ZERO(&set);
switch (fork()) {
case -1: { /* Error */
fprintf(stderr, "fork error\n");
exit(EXIT_FAILURE);
}
case 0: { /* Child */
CPU_SET(childCPU, &set);
if (sched_setaffinity(getpid(), sizeof(set), &set) == -1) {
fprintf(stderr, "child sched_setaffinity error\n");
exit(EXIT_FAILURE);
}
sleep(1);
if (-1 != (cpu_num = sched_getcpu())) {
fprintf(stdout, "The child process is running on cpu %d, the process id is %d\n", cpu_num, getpid());
}
usleep(1000 * 1000 * 60);
exit(EXIT_SUCCESS);
}
default: { /* Parent */
CPU_SET(parentCPU, &set);
if (sched_setaffinity(getpid(), sizeof(set), &set) == -1) {
fprintf(stderr, "parent sched_setaffinity error\n");
exit(EXIT_FAILURE);
}
if (-1 != (cpu_num = sched_getcpu())) {
fprintf(stdout, "The parent process is running on cpu %d, the process id is %d\n", cpu_num, getpid());
}
printf("Wait for child to terminate \n");
wait(NULL); /* Wait for child to terminate */
exit(EXIT_SUCCESS);
}
}
return 0;
}
二、线程绑核C语言实现
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <unistd.h>
#define handle_error_en(en, msg) \
do { errno = en; perror(msg); exit(EXIT_FAILURE); } while (0)
int cpu_num;
struct thread_info {
pthread_t thread_id;
int thread_num;
};
static void *thread_start(void *arg) {
struct thread_info *tinfo = (struct thread_info *)arg;
pthread_t thread = tinfo->thread_id;
cpu_set_t cpuset;
CPU_ZERO(&cpuset);
CPU_SET(tinfo->thread_num, &cpuset);
int s = pthread_setaffinity_np(thread, sizeof(cpu_set_t), &cpuset);
if (s != 0) {
handle_error_en(s, "pthread_setaffinity_np");
}
CPU_ZERO(&cpuset);
s = pthread_getaffinity_np(thread, sizeof(cpu_set_t), &cpuset);
if (s != 0) {
handle_error_en(s, "pthread_getaffinity_np");
}
for (int j = 0; j < cpu_num; j++) {
if (CPU_ISSET(j, &cpuset)) { //如果当前线程运行在CPU j上,则输出信息
printf(" thread %d is running on cpu %d\n", tinfo->thread_num, j);
}
}
pthread_exit(NULL);
}
int main(int argc, char *argv[])
{
cpu_num = sysconf(_SC_NPROCESSORS_CONF); //获取系统的CPU数量
struct thread_info *tinfo = (struct thread_info*)calloc(cpu_num, sizeof(struct thread_info));
if (tinfo == NULL) {
handle_error_en(0, "calloc");
}
for (int j = 0; j < cpu_num; j++) { //有多少个CPU就创建多少个线程
tinfo[j].thread_num = j;
int s = pthread_create(&tinfo[j].thread_id, NULL, thread_start, &tinfo[j]);
if (s != 0) {
handle_error_en(s, "pthread_create");
}
}
for (int j = 0; j < cpu_num; j++) {
int s = pthread_join(tinfo[j].thread_id, NULL);
if (s != 0) {
handle_error_en(s, "pthread_join");
}
}
return 0;
}
三、 shell命令绑核
任务集 (taskset) 是一个 Linux 命令,用于设置进程的 CPU 亲和度 (affinity),它可以将一个进程绑定到某个特定的 CPU 核心或一组 CPU 核心。
下面是 taskset 命令的具体使用:
- 绑定一个进程到单个 CPU 核心:
taskset -c <core_id> <command>
其中,<core_id> 是一个 CPU 核心的编号,从 0 开始; 是要执行的命令。
例如,要将进程绑定到第 1 个 CPU 核心上,可以使用以下命令:
taskset -c 0 command
- 绑定一个进程到多个 CPU 核心:
taskset -c <core_id_list> <command>
其中,<core_id_list> 是一个 CPU 核心编号的列表,用逗号分隔; 是要执行的命令。
例如,要将进程绑定到第 1、2、4 个 CPU 核心上,可以使用以下命令:
taskset -c 0,1,3 command
- 显示一个进程当前的 CPU 亲和度:
taskset -p <pid>
其中, pid是进程的 ID。
例如:
taskset -p 12345
- 修改一个正在运行的进程的 CPU 亲和度:
taskset -cp <core_id_list> <pid>
其中,<core_id_list> 是一个 CPU 核心编号的列表,用逗号分隔; 是正在运行的进程的 ID。
例如,要将进程 12345 绑定到第 1、2、4 个 CPU 核心上,可以使用以下命令:
taskset -cp 0,1,3 12345
# 查看某个进程在哪个cpu 上运行
ps -eLo ruser,pid,ppid,psr,args
# 查看cpu个数
cat /proc/cpuinfo |grep -c processor
# 查看进程所使用的CPU
taskset -cp 25718
# 调整进程所使用的CPU
taskset -p 25718
taskset -p 25718
taskset -c 1 25718
# 使用-p选项指定需要查询的进程号,默认打印的是一个十六进制数,如果使用-cp选项打印的是一个cpu列表,表示相应的cpu核