使用 sched_setaffinity 将线程绑到CPU核上运行

linux 提供CPU调度函数,可以将CPU某一个核和指定的线程绑定到一块运行。
这样能够充分利用CPU,且减少了不同CPU核之间的切换,尤其是在IO密集型压力之下能够提供较为友好的性能。

通过sched_setaffinity 设置 CPU 亲和力的掩码,从而将该线程或者进程和指定的CPU绑定

一个CPU的亲合力掩码用一个cpu_set_t结构体来表示一个CPU集合,下面的几个宏分别对这个掩码集进行操作:
CPU_ZERO() 清空一个集合
CPU_SET()CPU_CLR()分别对将一个给定的CPU号加到一个集合或者从一个集合中去掉.
CPU_ISSET()检查一个CPU号是否在这个集合中

  • 头文件 sched.h
  • sched_setaffinity(pid_t pid, unsigned int cpusetsize, cpu_set_t *mask)
    该函数设置进程为pid的这个进程,让它运行在mask所设定的CPU上.
    • 如果pid的值为0,则表示指定的是当前进程,使当前进程运行在mask所设定的那些CPU上.
    • 第二个参数cpusetsize是mask所指定的数的长度.通常设定为sizeof(cpu_set_t).如果当前pid所指定的进程此时没有运行在mask所指定的任意一个CPU上,则该指定的进程会从其它CPU上迁移到mask的指定的一个CPU上运行.
    • mask 即用户 通过CPU_SET 接口,线程ID 绑定刀片集合中的一个CPU上,使用mask来表示cpu集合中的CPU
  • sched_getaffinity(pid_t pid, unsigned int cpusetsize, cpu_set_t *mask)
    该函数获得pid所指示的进程的CPU位掩码,并将该掩码返回到mask所指向的结构中.即获得指定pid当前可以运行在哪些CPU上.同样,如果pid的值为0.也表示的是当前进程

使用方式如下:

#include 
#include 
#include 
#include 
#include 

#define __USE_GNU
#include 
#include 

int num;

void *thread_func1(void *arg) {
   cpu_set_t mask;  //CPU核的集合
   cpu_set_t get;   //获取在集合中的CPU
   int *a = (int*)arg; 
   printf("the a is:%d\n",*a);  //显示是第几个线程
   CPU_ZERO(&mask);    //置空
   CPU_SET(*a,&mask);   // 将当前线程和CPU绑定
   if(sched_setaffinity(0, sizeof(mask), &mask)) {
      printf("warning ! set affinity failed! \n");      
   } else {
         while (1)
         {
                   CPU_ZERO(&get);
                   if (sched_getaffinity(0, sizeof(get), &get) == -1)//获取线程CPU亲和力
                   {
                            printf("warning: cound not get thread affinity, continuing...\n");
                   }
                   int i;
                   for (i = 0; i < num; i++)
                   {
                            if (CPU_ISSET(i, &get))//判断线程与哪个CPU有亲和力
                            {
                                     printf("this thread %d is running processor : %d\n", i,i);
                            }
                   }
 
          }
     }
     return NULL; 
}

void *thread_func2(void *arg) {
   
   cpu_set_t mask;  //CPU核的集合
   cpu_set_t get;   //获取在集合中的CPU
   int *a = (int*)arg; 
   printf("the a is:%d\n",*a);  //显示是第几个线程
   CPU_ZERO(&mask);    //置空
   CPU_SET(*a,&mask);   // 将当前线程和CPU绑定
   if(sched_setaffinity(0, sizeof(mask), &mask) == -1) {
      printf("warning ! set affinity failed! \n");      
   } else {
         while (1)
         {
                   CPU_ZERO(&get);
                   if (sched_getaffinity(0, sizeof(get), &get) == -1)//获取线程CPU亲和力
                   {
                            printf("warning: cound not get thread affinity, continuing...\n");
                   }
                   int i;
                   for (i = 0; i < num; i++)
                   {
                            if (CPU_ISSET(i, &get))//判断线程与哪个CPU有亲和力
                            {
                                     printf("this thread %d is running processor : %d\n", i,i);
                            }
                   }
 
          }
  }
     return NULL; 
}

int main() {
 pthread_t t1;
 pthread_t t2;
 int t_1 = 0;
 int t_2 = 1;
 
 // 获取CPU核数
 num = sysconf(_SC_NPROCESSORS_CONF);

 // 需要传入t_1,t_2,来作为线程的参数,用来核CPU核绑定
 pthread_create(&t1, NULL, (void *)thread_func1,&t_1);
 pthread_create(&t2, NULL, (void *)thread_func2,&t_2);

 pthread_join(t1, NULL);
 pthread_join(t2, NULL);
  
 printf("main thread end\n");

  return 0;
}

如果使用到pthread,则需要将pthread.h 放到sched.h之后,并在sched.h之前声明#define __USE_GNU
否则会出现undefined reference CPU_ZERO等错误

编译:
gcc sched_cpu.c -o sched_cpu -pthread
以上代码将两个线程分别绑定到0,1号CPU上

运行后的CPU 效果图如下:
使用 sched_setaffinity 将线程绑到CPU核上运行_第1张图片

你可能感兴趣的:(编程语言,#,编程语言C,#,linux操作系统:多线程管理)