天天看點

使用 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 <stdio.h>
#include <unistd.h>
#include <time.h>
#include <signal.h>
#include <string.h>

#define __USE_GNU
#include <sched.h>
#include <pthread.h>

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上