CPU親合力就是指在Linux系統中能夠將一個或多個進程綁定到一個或多個處理器上運行.
一個進程的CPU親合力掩碼決定了該進程將在哪個或哪幾個CPU上運行.在一個多處理器系統中,設置CPU親合力的掩碼可能會獲得更好的性能.
一個CPU的親合力掩碼用一個cpu_set_t結構體來表示一個CPU集合,下面的幾個宏分別對這個掩碼集進行操作:
·CPU_ZERO() 清空一個集合
·CPU_SET()與CPU_CLR()分別對將一個給定的CPU號加到一個集合或者從一個集合中去掉.
·CPU_ISSET()檢查一個CPU號是否在這個集合中.
下面兩個函數就是用來設置獲取線程CPU親和力狀態:
·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上運行.
·sched_getaffinity(pid_t pid, unsigned int cpusetsize, cpu_set_t *mask)
該函數獲得pid所指示的進程的CPU位掩碼,並將該掩碼返回到mask所指向的結構中.即獲得指定pid當前可以運行在哪些CPU上.同樣,如果pid的值為0.也表示的是當前進程
- cpu_set_t的定義
- # define __CPU_SETSIZE 1024
- # define __NCPUBITS (8 * sizeof (__cpu_mask))
- typedef unsigned long int __cpu_mask;
- # define __CPUELT(cpu) ((cpu) / __NCPUBITS)
- # define __CPUMASK(cpu) ((__cpu_mask) 1 << ((cpu) % __NCPUBITS))
- typedef struct
- {
- __cpu_mask __bits[__CPU_SETSIZE / __NCPUBITS];
- } cpu_set_t;
- # define __CPU_ZERO(cpusetp) \
- do { \
- unsigned int __i; \
- cpu_set_t *__arr = (cpusetp); \
- for (__i = 0; __i < sizeof (cpu_set_t) / sizeof (__cpu_mask); ++__i) \
- __arr->__bits[__i] = 0; \
- } while (0)
- # define __CPU_SET(cpu, cpusetp) \
- ((cpusetp)->__bits[__CPUELT (cpu)] |= __CPUMASK (cpu))
- # define __CPU_CLR(cpu, cpusetp) \
- ((cpusetp)->__bits[__CPUELT (cpu)] &= ~__CPUMASK (cpu))
- # define __CPU_ISSET(cpu, cpusetp) \
- (((cpusetp)->__bits[__CPUELT (cpu)] & __CPUMASK (cpu)) != 0)
cpu_set_t的定義 # define __CPU_SETSIZE 1024 # define __NCPUBITS (8 * sizeof (__cpu_mask)) typedef unsigned long int __cpu_mask; # define __CPUELT(cpu) ((cpu) / __NCPUBITS) # define __CPUMASK(cpu) ((__cpu_mask) 1 << ((cpu) % __NCPUBITS)) typedef struct { __cpu_mask __bits[__CPU_SETSIZE / __NCPUBITS]; } cpu_set_t; # define __CPU_ZERO(cpusetp) \ do { \ unsigned int __i; \ cpu_set_t *__arr = (cpusetp); \ for (__i = 0; __i < sizeof (cpu_set_t) / sizeof (__cpu_mask); ++__i) \ __arr->__bits[__i] = 0; \ } while (0) # define __CPU_SET(cpu, cpusetp) \ ((cpusetp)->__bits[__CPUELT (cpu)] |= __CPUMASK (cpu)) # define __CPU_CLR(cpu, cpusetp) \ ((cpusetp)->__bits[__CPUELT (cpu)] &= ~__CPUMASK (cpu)) # define __CPU_ISSET(cpu, cpusetp) \ (((cpusetp)->__bits[__CPUELT (cpu)] & __CPUMASK (cpu)) != 0)
測試代碼:
- #include<stdlib.h>
- #include<stdio.h>
- #include<sys/types.h>
- #include<sys/sysinfo.h>
- #include<unistd.h>
- #define __USE_GNU
- #include<sched.h>
- #include<ctype.h>
- #include<string.h>
- #include<pthread.h>
- #define THREAD_MAX_NUM 100 //1個CPU內的最多進程數
- int num=0; //cpu中核數
- void* threadFun(void* arg) //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); //設置親和力值
- if (sched_setaffinity(0, sizeof(mask), &mask) == -1)//設置線程CPU親和力
- {
- printf("warning: could not set CPU affinity, continuing...\n");
- }
- 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(int argc, char* argv[])
- {
- num = sysconf(_SC_NPROCESSORS_CONF); //獲取核數
- pthread_t thread[THREAD_MAX_NUM];
- printf("system has %i processor(s). \n", num);
- int tid[THREAD_MAX_NUM];
- int i;
- for(i=0;i<num;i++)
- {
- tid[i] = i; //每個線程必須有個tid[i]
- pthread_create(&thread[0],NULL,threadFun,(void*)&tid[i]);
- }
- for(i=0; i< num; i++)
- {
- pthread_join(thread[i],NULL);//等待所有的線程結束,線程為死循環所以CTRL+C結束
- }
- return 0;
- }
#include<stdlib.h> #include<stdio.h> #include<sys/types.h> #include<sys/sysinfo.h> #include<unistd.h> #define __USE_GNU #include<sched.h> #include<ctype.h> #include<string.h> #include<pthread.h> #define THREAD_MAX_NUM 100 //1個CPU內的最多進程數 int num=0; //cpu中核數 void* threadFun(void* arg) //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); //設置親和力值 if (sched_setaffinity(0, sizeof(mask), &mask) == -1)//設置線程CPU親和力 { printf("warning: could not set CPU affinity, continuing...\n"); } 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(int argc, char* argv[]) { num = sysconf(_SC_NPROCESSORS_CONF); //獲取核數 pthread_t thread[THREAD_MAX_NUM]; printf("system has %i processor(s). \n", num); int tid[THREAD_MAX_NUM]; int i; for(i=0;i<num;i++) { tid[i] = i; //每個線程必須有個tid[i] pthread_create(&thread[0],NULL,threadFun,(void*)&tid[i]); } for(i=0; i< num; i++) { pthread_join(thread[i],NULL);//等待所有的線程結束,線程為死循環所以CTRL+C結束 } return 0; }
編譯命令:gcc bind.c -o bind -lpthread
執行:./bind
輸出結果:略
特別注意:
#define __USE_GNU不要寫成#define _USE_GNU
#include<pthread.h>必須寫在#define __USE_GNU之后,否則編譯會報錯
查看你的線程情況可以在執行時在另一個窗口使用top -H來查看線程的情況,查看各個核上的情況請使用top命令然后按數字“1”來查看。