Linux:获取、设置进程(线程)的CPU亲和性

97 篇文章 7 订阅

Linux:设置进程(线程)的CPU亲和性


一、进程的CPU亲和性的获取(get)或者设置(set)

int sched_setaffinity(pid_t pid, size_t cpusetsize, cpu_set_t *mask);
int sched_getaffinity(pid_t pid, size_t cpusetsize, cpu_set_t *mask);

demo:主线程创建四个线程,获取主线程的CPU亲和性,设置四个非主线程的CPU亲和性

main.c

#define _GNU_SOURCE
#include <stdio.h>
#include <stdlib.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <pthread.h>
#include <sched.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/syscall.h>

pid_t gettid() {
	return syscall(SYS_gettid);
}

void *start_routine(void *arg)
{
	int thn = *((int *)arg);

	pid_t pid = gettid(); // LWP
	pthread_t tid = pthread_self();

	long cpu_num = sysconf(_SC_NPROCESSORS_ONLN);
	if (cpu_num <= 0) {
		printf("thn=%d,pid=%d,tid=%lu,get cpu info error:%ld\n",
				thn, pid, tid, cpu_num);
		return;
	}

	cpu_set_t cpu_set;
	CPU_ZERO(&cpu_set);
	CPU_SET(thn%cpu_num, &cpu_set);

	int res = sched_setaffinity(0 /* or pid */, sizeof(cpu_set), &cpu_set);
	if (res != 0) {
		printf("thn=%d,pid=%d,tid=%lu,sched_setaffinity error:%d(%s)\n",
				thn, pid, tid, res, strerror(res));
		return;
	}

	printf("thn=%d,pid=%d,tid=%lu,bind cpu[%d] ok!\n",
			thn, pid, tid, thn%cpu_num);

	while (1)
		sleep(1);
}

int main()
{
	int i0 = 0;
	pthread_t tid0;
	pthread_create(&tid0, NULL, start_routine, &i0);

	int i1 = 1;
	pthread_t tid1;
	pthread_create(&tid1, NULL, start_routine, &i1);

	int i2 = 2;
	pthread_t tid2;
	pthread_create(&tid2, NULL, start_routine, &i2);

	int i3 = 3;
	pthread_t tid3;
	pthread_create(&tid3, NULL, start_routine, &i3);

	cpu_set_t cpu_set;
	CPU_ZERO(&cpu_set);

	int res = sched_getaffinity(0 /* or getpid() */, sizeof(cpu_set), &cpu_set);
	if (res != 0) {
		printf("main: pid=%d,tid=%lu,sched_getaffinity error:%d(%s)\n",
				getpid(), pthread_self(), res, strerror(res));
		return;
	}
	int i = 0;
	for (; i < sizeof(cpu_set); i++) {
		if (CPU_ISSET(i, &cpu_set)) {
			printf("main: pid=%d,tid=%lu,bind cpu[%d]\n", getpid(), pthread_self(), i);
		}
	}

	while (1)
		sleep(1);
}

编译运行:

[test1280@localhost 20190305]$ gcc -o main main.c -lpthread
[test1280@localhost 20190305]$ ./main
main: pid=31387,tid=140119163442944,bind cpu[0]
thn=3,pid=31391,tid=140119131965184,bind cpu[3] ok!
main: pid=31387,tid=140119163442944,bind cpu[1]
main: pid=31387,tid=140119163442944,bind cpu[2]
main: pid=31387,tid=140119163442944,bind cpu[3]
thn=1,pid=31389,tid=140119152944896,bind cpu[1] ok!
thn=0,pid=31388,tid=140119163434752,bind cpu[0] ok!
thn=2,pid=31390,tid=140119142455040,bind cpu[2] ok!
^C

主线程(PID=31387)创建了四个线程(PID=31388、31389、31390、31391)。

PID=31387 可运行在 CPU0、CPU1、CPU2、CPU3
PID=31388 可运行在 CPU0
PID=31389 可运行在 CPU1
PID=31390 可运行在 CPU2
PID=31391 可运行在 CPU3

[test1280@localhost 20190305]$ taskset -pc 31387
pid 31387's current affinity list: 0-3
[test1280@localhost 20190305]$ taskset -pc 31391
pid 31391's current affinity list: 3
[test1280@localhost 20190305]$ taskset -pc 31389
pid 31389's current affinity list: 1
[test1280@localhost 20190305]$ taskset -pc 31388
pid 31388's current affinity list: 0
[test1280@localhost 20190305]$ taskset -pc 31390
pid 31390's current affinity list: 2

通过 taskset 命令可进行验证。

关于 cpu_set_t 类型,类似于 fd_set(select),有几个宏可直接对“位集”进行操作:

void CPU_ZERO(cpu_set_t *set);
void CPU_SET(int cpu, cpu_set_t *set);
void CPU_CLR(int cpu, cpu_set_t *set);
int  CPU_ISSET(int cpu, cpu_set_t *set);
……
The affinity mask is actually a per-thread attribute that can be adjusted independently for each of the threads in a thread group.

CPU亲和性是线程级属性,能够被独立地(与其他线程无关)地设置或获取。

线程是最小的调度执行单元,理所应当地,是线程运行在某CPU之上,亲和性是线程的一个属性。

需要注意,这两个系统调用的第一个参数pid,都是内核分配的PID(TID、LWP),而非 pthread_t 类型。

准确地说,没有能设置、获取整个进程的CPU亲和性的接口,只有能设置、获取某线程的CPU亲和性的接口。


二、线程的CPU亲和性的获取(get)或者设置(set)

int pthread_setaffinity_np(pthread_t thread, size_t cpusetsize, const cpu_set_t *cpuset);
int pthread_getaffinity_np(pthread_t thread, size_t cpusetsize, cpu_set_t *cpuset);

demo:主线程创建四个线程,获取主线程的CPU亲和性,设置四个非主线程的CPU亲和性

main.c

#define _GNU_SOURCE
#include <stdio.h>
#include <stdlib.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <pthread.h>
#include <sched.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/syscall.h>

pid_t gettid() {
	return syscall(SYS_gettid);
}

void *start_routine(void *arg)
{
	int thn = *((int *)arg);

	pid_t pid = gettid(); // LWP
	pthread_t tid = pthread_self();

	long cpu_num = sysconf(_SC_NPROCESSORS_ONLN);
	if (cpu_num <= 0) {
		printf("thn=%d,pid=%d,tid=%lu,get cpu info error:%ld\n",
				thn, pid, tid, cpu_num);
		return;
	}

	cpu_set_t cpu_set;
	CPU_ZERO(&cpu_set);
	CPU_SET(thn%cpu_num, &cpu_set);

	int res = pthread_setaffinity_np(tid, sizeof(cpu_set), &cpu_set);
	if (res != 0) {
		printf("thn=%d,pid=%d,tid=%lu,pthread_setaffinity_np error:%d(%s)\n",
				thn, pid, tid, res, strerror(res));
		return;
	}

	printf("thn=%d,pid=%d,tid=%lu,bind cpu[%d] ok!\n",
			thn, pid, tid, thn%cpu_num);

	while (1)
		sleep(1);
}

int main()
{
	int i0 = 0;
	pthread_t tid0;
	pthread_create(&tid0, NULL, start_routine, &i0);

	int i1 = 1;
	pthread_t tid1;
	pthread_create(&tid1, NULL, start_routine, &i1);

	int i2 = 2;
	pthread_t tid2;
	pthread_create(&tid2, NULL, start_routine, &i2);

	int i3 = 3;
	pthread_t tid3;
	pthread_create(&tid3, NULL, start_routine, &i3);

	cpu_set_t cpu_set;
	CPU_ZERO(&cpu_set);

	int res = pthread_getaffinity_np(pthread_self(), sizeof(cpu_set), &cpu_set);
	if (res != 0) {
		printf("main: pid=%d,tid=%lu,pthread_getaffinity_nperror:%d(%s)\n",
				getpid(), pthread_self(), res, strerror(res));
		return;
	}
	int i = 0;
	for (; i < sizeof(cpu_set); i++) {
		if (CPU_ISSET(i, &cpu_set)) {
			printf("main: pid=%d,tid=%lu,bind cpu[%d]\n", getpid(), pthread_self(), i);
		}
	}

	while (1)
		sleep(1);
}

运行输出:

[test1280@localhost 20190305]$ ./main
main: pid=31765,tid=140313705346816,bind cpu[0]
main: pid=31765,tid=140313705346816,bind cpu[1]
main: pid=31765,tid=140313705346816,bind cpu[2]
main: pid=31765,tid=140313705346816,bind cpu[3]
thn=0,pid=31766,tid=140313705338624,bind cpu[0] ok!
thn=1,pid=31767,tid=140313694848768,bind cpu[1] ok!
thn=3,pid=31769,tid=140313673869056,bind cpu[3] ok!
thn=2,pid=31768,tid=140313684358912,bind cpu[2] ok!
^C
[test1280@localhost 20190305]$ taskset -pc 31765
pid 31765's current affinity list: 0-3
[test1280@localhost 20190305]$ taskset -pc 31766
pid 31766's current affinity list: 0
[test1280@localhost 20190305]$ taskset -pc 31767
pid 31767's current affinity list: 1
[test1280@localhost 20190305]$ taskset -pc 31768
pid 31768's current affinity list: 2
[test1280@localhost 20190305]$ taskset -pc 31769
pid 31769's current affinity list: 3

pthread_setaffinity_np 以及 pthread_getaffinity_np 是 libpthread 库(man 3) 实现的接口,底层实现基于系统调用(man 2) sched_setaffinity 以及 sched_setscheduler。

man pthread_getaffinity_np
These functions are implemented on top of the sched_setaffinity(2) and sched_getaffinity(2) system calls.

既然是 libpthread 库实现的接口,使用的线程标识符也是 libpthread 库自定义的 pthread_t 类型,而非 pid_t。

libpthread 库实现的这两个接口是不可移植的,所以函数名带了 _np 后缀标识(non-portable)。

man pthread_getaffinity_np
These functions are non-standard GNU extensions; hence the suffix "_np" (non-portable) in the names.

通过 pthread_create 创建的线程将 继承 原线程的CPU亲和性属性值。

man pthread_getaffinity_np
A new thread created by pthread_create() inherits a copy of its creator’s CPU affinity mask.

参考:

1.https://www.cnblogs.com/wenqiang/p/6049978.html
2.https://www.cnblogs.com/LubinLew/p/cpu_affinity.html

相关:

1.https://blog.csdn.net/test1280/article/details/87993669
2.https://blog.csdn.net/test1280/article/details/87991302
3.https://blog.csdn.net/test1280/article/details/87974748

  • 0
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值