Chinaunix首页 | 论坛 | 博客
  • 博客访问: 1990370
  • 博文数量: 369
  • 博客积分: 10093
  • 博客等级: 上将
  • 技术积分: 4271
  • 用 户 组: 普通用户
  • 注册时间: 2005-03-21 00:59
文章分类

全部博文(369)

文章存档

2013年(1)

2011年(2)

2010年(10)

2009年(16)

2008年(33)

2007年(146)

2006年(160)

2005年(1)

分类: LINUX

2007-10-13 11:32:46

进程和线程的亲缘性(affinity)是指可以将进程或者是线程强制限制在可用的CPU子集上运行的特性,它一定程度上把进程/线程在多处理器系统上的调度策略暴露给系统程序员,有助于程序员实现自己的调度策略以提供特定情况下的更好性能,NUMA(非统一内存访问)就是这样一种计算机结构。

CPU的数量和表示

在有n个CPU的Linux上,CPU是用0...n-1来进行一一标识的。CPU的数量可以通过proc文件系统下的CPU相关文件得到,如cpuinfo和stat:

[xiaosuo@MagicLinux test]$ cat /proc/stat | grep "^cpu[0-9]\+" | wc -l
8
[xiaosuo@MagicLinux test]$ cat /proc/cpuinfo | grep "^processor" | wc -l
8

在系统编程中,可以直接调用库调用sysconf获得:

sysconf(_SC_NPROCESSORS_ONLN);

进程的亲缘性

Linux操作系统在2.5.8引入了调度亲缘性相关的系统调用:

int sched_setaffinity(pid_t pid, unsigned int cpusetsize, cpu_set_t *mask);

int sched_getaffinity(pid_t pid, unsigned int cpusetsize, cpu_set_t *mask);


其中sched_setaffinity是设定进程号为pid的进程调度亲缘性为mask,也就是说它只能在mask中指定的CPU之间进行调度执行;sched_getaffinity当然就是得到进程号为pid的进程调度亲缘性了。如果pid为0,则操纵当前进程。

第二个参数指定mask所指空间的大小,通常为sizeof(cpu_set_t)。

第三个参数mask的类型为cpu_set_t,即CPU集合,GNU的c库(需要在include头文件之前定义__USE_GNU)还提供了操作它们的宏:

void CPU_CLR(int cpu, cpu_set_t *set);
int CPU_ISSET(int cpu, cpu_set_t *set);
void CPU_SET(int cpu, cpu_set_t *set);
void CPU_ZERO(cpu_set_t *set);

线程的亲缘性

Windows系统下的进程亲缘性和线程亲缘性是分别设置的,Linux与此不同,他只提供了面向线程的调度亲缘性一种接口,这也是上面只提调度亲缘性而不直言进程亲缘性的原因。当前Linux系统下广泛采用的线程库NPTL(Native Posix Thread Library)是基于线程组来实现的,同一个线程组中的线程对应于一组共享存储空间的轻量级进程,它们各自作为单独调度单位被内核的调度器在系统范围内调度,这种模型也就是我们通常所说的1-1线程模型。正因如此,目前线程的调度范围(可以用函数pthread_attr_getscope和pthread_attr_setscope获取和设置)只能是系统级而不能是进程级,不过依形式来看,这种状况将在不久的将来通过引入控制组(以前的名字是)来解决。现在回到原题,c库的GNU扩展所提供的有关线程亲缘性的API如下:

int pthread_attr_setaffinity_np (pthread_attr_t *__attr, size_t __cpusetsize, __const cpu_set_t *__cpuset);


int pthread_attr_getaffinity_np (__const pthread_attr_t *__attr, size_t __cpusetsize, cpu_set_t *__cpuset);


int pthread_setaffinity_np (pthread_t __th, size_t __cpusetsize, __const cpu_set_t *__cpuset);


int pthread_getaffinity_np (pthread_t __th, size_t __cpusetsize, cpu_set_t *__cpuset);

亲缘性的继承

调度亲缘性是被fork出来的子进程所继承的,即使子进程通过exec系列函数更换了执行镜像。因为Linux操作系统下进程和线程的创建都是通过系统调用clone来实现的,所以实际上调度亲缘性也是被用pthread_create创建的线程所继承的。这意味着,如果主线程在创建其它线程之前设定亲缘性,那么它所设定的亲缘性将被继承,因为这时所有线程的亲缘性相同(假设之后没有任何线程私自设置亲缘性),我们就可以认为前面设置的是进程亲缘性,而不管它所调用的函数是sched_setaffinity还是pthread_setaffnity_np。

其它

目前,在亲缘性这方面,Linux相对于Windows还缺少类似SetThreadIdealProcessor的设定理想CPU集合的系统调用。另外,基于文件的亲缘性(在可执行文件中保存亲缘性)Linux也不支持,如果能顺利进驻内核,那么这个也应该没啥问题。
阅读(7796) | 评论(0) | 转发(1) |
给主人留下些什么吧!~~