linux多线程:设置线程属性之CPU核绑定

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

      不管是线程还是进程,都是通过设置亲和性(affinity)来达到目的。实际应用中通常需要将软件下的各个子任务分配各个核上运行,提高软件的运行效率。

目录

1、设置/获取进程间的CPU亲缘性(通过进程pid)

2、设置/获取线程间的CPU亲缘性(通过线程属性指针)

3、设置/获取线程的CPU亲缘性(通过线程结构 / Id )

4、cpu_set_t 结构体

5、函数测试

6、注意事项


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亲核性的接口时需要注意头文件,宏定义等

 

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

老王不让用

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值