不管是线程还是进程,都是通过设置亲和性(affinity)来达到目的。实际应用中通常需要将软件下的各个子任务分配各个核上运行,提高软件的运行效率。
目录
3、设置/获取线程的CPU亲缘性(通过线程结构 / Id )
1、设置/获取进程间的CPU亲缘性(通过进程pid)
#define _GNU_SOURCE
#include <sched.h>
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);
参 数:pid表示进程号,如果是pid=0,则表示当前进程
返回值:若是成功返回0,否则返回错误的编号
2、设置/获取线程间的CPU亲缘性(通过线程属性指针)
#define _GNU_SOURCE
#include <pthread.h>
int pthread_attr_setaffinity_np(pthread_attr_t *attr,
size_t cpusetsize, const cpu_set_t *cpuset);
int pthread_attr_getaffinity_np(pthread_attr_t *attr,
size_t cpusetsize, cpu_set_t *cpuset);
Compile and link with -pthread.
参 数:
attr 指向一个线程属性的指针
cpusetsize 指向CPU组的缓冲区大小
cpuset 指向CPU组的指针
返回值:若是成功返回0,否则返回错误的编号
3、设置/获取线程的CPU亲缘性(通过线程结构 / Id )
#define _GNU_SOURCE
#include <pthread.h>
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);
Compile and link with -pthread.
参 数:
thread 线程ID
cpusetsize 指向CPU组的缓冲区大小
cpuset 指向CPU组的指针
返回值:若是成功返回0,否则返回错误的编号
4、cpu_set_t 结构体
以上的函数名以及参数名都很明了,唯一需要点解释下的可能就是cpu_set_t这个结构体了。这个结构体的理解类似于select中的fd_set,可以理解为cpu集,也是通过约定好的宏来进行清除、设置以及判断:
//初始化,设为空
void CPU_ZERO (cpu_set_t *set);
//将某个cpu加入cpu集中
void CPU_SET (int cpu, cpu_set_t *set);
//将某个cpu从cpu集中移出
void CPU_CLR (int cpu, cpu_set_t *set);
//判断某个cpu是否已在cpu集中设置了
int CPU_ISSET (int cpu, const cpu_set_t *set);
CPU 集可以认为是一个掩码,每个设置的位都对应一个可以合法调度的 CPU,而未设置的位则对应一个不可调度的 CPU。换而言之,线程都被绑定了,只能在那些对应位被设置了的处理器上运行。通常,掩码中的所有位都被置位了,也就是可以在所有的 CPU 中调度。
5、函数测试
#define _GNU_SOURCE
#include <stdio.h>
#include <pthread.h>
//#define __USE_GNU
#include <sched.h>//使用 CPU_ZERO、CPU_SET等宏
#include <sys/prctl.h>
void printSelfThreadInfo(const char *s,int cnt);
void *childThread(void *arg);
void *childChildThread(void *arg);
#define SYS_SUCC 0
#define SYS_ERR -1
#define SYS_CORE_ID 2
int main(int argc,char **argv)
{
int sysRet = -1;
pthread_t threadId;
pthread_attr_t threadAttr;
cpu_set_t cpuSetInfo,cpuGetInfo;
cpu_set_t cpuSetProcInfo,cpuGetProcInfo;
printf("process pid = %d\n",getpid());
CPU_ZERO(&cpuSetInfo);
CPU_SET(SYS_CORE_ID, &cpuSetInfo);//添加core2到cpu集合中
CPU_ZERO(&cpuSetProcInfo);
CPU_SET(SYS_CORE_ID, &cpuSetProcInfo);
CPU_SET(SYS_CORE_ID + 1, &cpuSetProcInfo);
CPU_SET(SYS_CORE_ID + 2, &cpuSetProcInfo);
sysRet=sched_setaffinity(0,sizeof(cpuSetProcInfo),&cpuSetProcInfo);//pid = 0 表示设置当前进程
if(sysRet == SYS_ERR)
{
printf("set cpu affinity failed");
return SYS_ERR;
}
/*
pthread_attr_init(&threadAttr);
sysRet = pthread_attr_setaffinity_np(&threadAttr, sizeof(cpu_set_t), &cpuSetInfo);
if (sysRet == SYS_ERR)
{
printf("set cpu affinity failed");
return SYS_ERR;
}
sysRet = pthread_create(&threadId,&threadAttr,childThread,NULL);
if(sysRet == SYS_ERR)
{
printf("can't create childThread...\n");
return SYS_ERR;
}
sysRet = pthread_attr_getaffinity_np(&threadAttr, sizeof(cpu_set_t), &cpuGetInfo);
if (sysRet == SYS_ERR)
{
printf("get cpu affinity failed");
return SYS_ERR;
}
printf("core %d is setted ? :%d\n",SYS_CORE_ID,CPU_ISSET(SYS_CORE_ID, &cpuGetInfo));
pthread_join(threadId,NULL);
pthread_attr_destroy(&threadAttr);
return SYS_SUCC;
*/
sysRet = pthread_create(&threadId,NULL,childThread,NULL);
if(sysRet == SYS_ERR)
{
printf("can't create childThread...\n",threadId,sizeof(threadId));
return SYS_ERR;
}
printf("threadId = %d,len=%d\n",threadId,sizeof(threadId));
sysRet = pthread_setaffinity_np(threadId, sizeof(cpu_set_t), &cpuSetInfo);
if (sysRet == SYS_ERR)
{
printf("set cpu affinity failed");
return SYS_ERR;
}
sysRet = pthread_getaffinity_np(threadId, sizeof(cpu_set_t), &cpuGetInfo);
if (sysRet == SYS_ERR)
{
printf("get cpu affinity failed");
return SYS_ERR;
}
printf("core %d is setted ? :%d\n",SYS_CORE_ID,CPU_ISSET(SYS_CORE_ID, &cpuGetInfo));
pthread_join(threadId,NULL);
pthread_attr_destroy(&threadAttr);
return SYS_SUCC;
}
void *childThread(void *arg)
{
int sysRet = -1;
char threadName[16];
pthread_t threadId;
prctl(PR_SET_NAME,"childThread");
prctl(PR_GET_NAME, threadName);
sysRet = pthread_create(&threadId,NULL,childChildThread,NULL);
if(sysRet == SYS_ERR)
{
printf("can't create childChildThread...\n");
return ;
}
for(;;)
{
sleep(1);
}
}
void *childChildThread(void *arg)//绑核属性自动继承
{
char threadName[16];
prctl(PR_SET_NAME,"childChildThread");
prctl(PR_GET_NAME, threadName);
for(;;)
{
sleep(1);
}
}
运行结果:

主线程绑定的CPU核为:2,3,4 // mask二进制值为:11100(1c)
"childThread"绑定的CPU核为:2 // mask二进制值为:100(4)
"childChildThread"绑定的CPU核为:2 // mask二进制值为:100(4) //绑核属性实现了继承
6、注意事项
1、CPU亲和性具有继承的属性
2、cpu_set_t 是一个CPU核的集合,可以指定多个,实际应用中指定一个就行,以免进程出现飘核
3、使用设置CPU亲核性的接口时需要注意头文件,宏定义等

本文详细介绍了如何在Linux环境下通过设置进程和线程的CPU亲和性来优化多核处理器上的软件运行效率。包括使用sched_setaffinity、pthread_attr_setaffinity_np和pthread_setaffinity_np函数进行设置的方法,以及如何获取当前的CPU亲和性设置。
557

被折叠的 条评论
为什么被折叠?



