1.对使用的介绍讲述的挺清晰
http://www.oenhan.com/cpu-affinity
2.对该机制原理进行了阐述
http://www.ibm.com/developerworks/cn/linux/l-affinity.html
其实CPU affinity就是可以让某个进程/线程在指定的CPU上运行.在默认情况下,调度算法具有软亲和性,即它可以在任意的核上运行.实现上其实就是cpu的bit数组全位1.
过会会对它的实现机制,进行分析,并自己根据glib自己编写了代码.
CPU affinity会用到两个函数sched_setaffinity和sched_getaffinity.
下面简单演示如何使用它:
#include
#include
#include
#include
#include
#define __USE_GNU
#include
#include
#include
int main(int argc, char* argv[])
{
int num = sysconf(_SC_NPROCESSORS_CONF);
int cpuid;
cpu_set_t mask;
cpu_set_t get;
if (argc != 2)
{
printf("usage : ./cpu num\n");
exit(1);
}
cpuid = atoi(argv[1]);
printf("system has %i processor(s). \n", num);
CPU_ZERO(&mask);
CPU_SET(cpuid, &mask);
if (sched_setaffinity(0, sizeof(mask), &mask) == -1)
{
printf("没有设置成功,此时cpuset集全为1,即可以运行在所以核上\n");
}
int i;
while (1)
{
CPU_ZERO(&get);
if (sched_getaffinity(0, sizeof(get), &get) == -1)
{
printf("warning: cound not get cpu affinity, continuing...\n");
}
for (i = 0; i < num; i++)
{
if (CPU_ISSET(i, &get))
{
printf("this process %d is running processor : %d\n",getpid(), i);
}
}
}
return 0;
}
我的机制只有两个逻辑处理器,你也可以在shell中查看,cat /proc/cpuinfo
此时为processor 0 和 processor 1
运行 ./a.out 0 (或./a.out 1),就可以看到当前进程只运行在cpu0上(或cpu1上)
运行./a.out 2或其他数字,此时sched_setaffinity失败,所以此时还是默认情况,即可以运行任意cpu上,因此,看到当前进程运行在两个核上.
修改掩码需要用到以下的宏
void CPU_ZERO (cpu_set_t *set) 这个宏对 CPU 集 set 进行初始化,将其设置为空集。 void CPU_SET (int cpu, cpu_set_t *set) 这个宏将 cpu 加入 CPU 集 set 中。 void CPU_CLR (int cpu, cpu_set_t *set) 这个宏将 cpu 从 CPU 集 set 中删除。 int CPU_ISSET (int cpu, const cpu_set_t *set) 如果 cpu 是 CPU 集 set 的一员,这个宏就返回一个非零值(true),否则就返回零(false)。其实本质上就是对位数组的位操作而已,下面根据glic sched.h中的源码自己实现了一下.
代码如下:
#include
#include
#include
#include
#define __CPU_SETSIZE 1024
#define __NCPUBITS (8 * sizeof(__mycpu_mask) )
typedef long int __mycpu_mask;//32位机器大小为4B,64位大小位8B
//create mycpu_set_t with bit array
typedef struct{
__mycpu_mask __bits[__CPU_SETSIZE / __NCPUBITS];//不采用int数组,而根据cpu字长来采用相应类型数组,能够提高效率
}mycpu_set_t;
#define MYCPU_ZERO(cpusetp) \
do{ \
mycpu_set_t *arr = (cpusetp); \
unsigned int __i; \
for(__i = 0; __i < __CPU_SETSIZE / __NCPUBITS; __i++) \
{ \
arr->__bits[__i] = 0; \
} \
}while(0)
#define __POS(cpuid) ((cpuid) / __NCPUBITS) //该cpuid在bits数组的哪个单元上
#define __CPUMASK(cpuid) ( 1 << ((cpuid) % __NCPUBITS) )//该cpuid在单元的那个位上.
#define MYCPU_SET(cpuid, cpusetp) \
( (cpusetp)->__bits[__POS(cpuid)] |= __CPUMASK(cpuid) )
#define MYCPU_CLR(cpuid,cpusetp) \
( ((cpusetp)->__bits[__POS(cpuid)] ) &= ~__CPUMASK(cpuid) )
#define MYCPU_ISSET(cpuid, cpusetp) \
( ((cpusetp)->__bits[__POS(cpuid)] & __CPUMASK(cpuid)) != 0 )
//int main()
//{
// mycpu_set_t mask;
// MYCPU_ZERO(&mask);
// int i;
// for(i = 0; i < __CPU_SETSIZE / __NCPUBITS; i++)
// {
// printf("%d ", mask.__bits[i]);
// }
// printf("\n");
// MYCPU_SET(3,&mask);
// for(i = 0; i < __CPU_SETSIZE / __NCPUBITS; i++)
// {
// printf("%d ", mask.__bits[i]);
// }
// printf("\n");
// MYCPU_CLR(3,&mask);
// for(i = 0; i < __CPU_SETSIZE / __NCPUBITS; i++)
// {
// printf("%d ", mask.__bits[i]);
// }
// printf("\n");
// MYCPU_SET(1,&mask);
// MYCPU_SET(2,&mask);
// MYCPU_SET(3,&mask);
// MYCPU_SET(4,&mask);
// printf("testing MYCPU_ISSET:\n");
// for(i = 0; i < __CPU_SETSIZE / __NCPUBITS; i++)
// {
// if(MYCPU_ISSET(i, &mask))
// printf("%d ", i);
// }
// printf("\n");
// return 0;
//}
void test()
{
int num_processors = sched_getcpu();
printf("%d\n", num_processors);
}
void *threadFun(void *arg)
{
mycpu_set_t mask;
mycpu_set_t get;
int *id = (int *)arg;
printf("the thread is:%d\n", *id);
MYCPU_ZERO(&mask);
MYCPU_SET(*id, &mask);
if(sched_setaffinity(0, sizeof(mask), &mask) == -1)
{
printf("warning: could not set CPU affinity\n");
}
MYCPU_ZERO(&get);
if(sched_getaffinity(0, sizeof(get), &get) == -1)
{
printf("warning :could not get thread affinity\n");
}
int i;
int num_procs = sysconf(_SC_NPROCESSORS_CONF);
for(i = 0; i < num_procs; i++)
{
if(MYCPU_ISSET(i, &get))
{
printf("this thread %d is running processor:%d\n", *id, i);
}
}
return NULL;
}
int main(void)
{
int num_procs = sysconf(_SC_NPROCESSORS_CONF);
pthread_t thread[num_procs];
int id[num_procs];
int i;
for(i = 0; i < num_procs; i++)
{
id[i] = i;
pthread_create(&thread[i], NULL, threadFun, (void *)&id[i]);
}
for(i = 0; i < num_procs; i++)
{
pthread_join(thread[i], NULL);
}
test();
return 0;
}
结果如下:
可以看到0号线程运行在处理器0上,1号线程运行在处理器1上