看到很多程序都是根据CPU个数来创建线程个数,当时很不理解他们之间的关系,请教了项目组的同事后才有了大致了解。
1. 相关系统函数
下面的函数可以通过man命令查询到。SYNOPSIS
#define _GNU_SOURCE
#include
int pthread_setaffinity_np(pthread_t thread, size_t cpusetsize,
const cpu_set_t *cpuset);
int pthread_getaffinity_np(pthread_t thread, size_t cpusetsize,
cpu_set_t *cpuset);
Compile and link with -pthread.
DESCRIPTION
The pthread_setaffinity_np() sets the CPU affinity mask of the thread thread to the CPU set pointed to by cpuset. If the call is successful, and the thread is
not currently running on one of the CPUs in cpuset, then it is migrated to one of those CPUs.
The pthread_getaffinity_np() function returns the CPU affinity mask of the thread thread in the buffer pointed to by cpuset.
For more details on CPU affinity masks, see sched_setaffinity(2). For a description of a set of macros that can be used to manipulate and inspect CPU sets, see
CPU_SET(3).
The argument cpusetsize is the length (in bytes) of the buffer pointed to by cpuset. Typically, this argument would be specified as sizeof(cpu_set_t). (It may
be some other value, if using the macros described in CPU_SET(3) for dynamically allocating a CPU set.)
RETURN VALUE
On success, these functions return 0; on error, they return a non-zero error number.
简而言之,这两个函数一个设置在哪个CPU核上运行,另一个获取设置的参数(mask),既可以查询出当前进程在运行在哪个核上
CPU_ZERO() Clears set, so that it contains no CPUs.
设置为空,没有任何CPU
CPU_SET() Add CPU cpu to set.
将某个核加入CPU集合
CPU_CLR() Remove CPU cpu from set.
将某个核清理出CPU集合
CPU_ISSET() Test to see if CPU cpu is a member of set.
判断某个核是否在CPU集合中设置。cpu集合可以认为是一个掩码,每个设置的位都对应一个可以合法调度的 cpu,而未设置的位则对应一个不可调度的 CPU。换而言之,线程都被绑定了,只能在那些对应位被设置了的处理器上运行。通常,掩码中的所有位都被置位了,也就是可以在所有的cpu中调度。
CPU_COUNT() Return the number of CPUs in set.
2.下面是我的测试代码。
测试环境:
系统: SUSE 10
linux 内核版本:2.6.32.12
CPU: 8核
2.1 根据CPU核个数创建线程,并绑定
void *myfunWithMultiThread(void *arg)
{
cpu_set_t mask;
cpu_set_t get;
int i = 0;
int num = 0;
int cpuID = *(int *)arg;
CPU_ZERO(&mask);
CPU_SET(cpuID, &mask);
if (pthread_setaffinity_np(pthread_self(), sizeof(mask), &mask) < 0) {
fprintf(stderr, "set thread affinity failed\n");
}
CPU_ZERO(&get);
if (pthread_getaffinity_np(pthread_self(), sizeof(get), &get) < 0) {
fprintf(stderr, "get thread affinity failed\n");
}
num = sysconf(_SC_NPROCESSORS_CONF);
for (i = 0; i < num; i++) {
if (CPU_ISSET(i, &get)) {
printf("thread %d is running in processor %d\n", (int)pthread_self(), i);
printf("Original setting is in processor %d\n\n", cpuID);
}
}
sleep(10);
}
int main(int argc, char *argv[])
{
pthread_t tid;
int num = 0;
int i =0;
num = sysconf(_SC_NPROCESSORS_CONF);
int id[16];
printf("System has %d processor(s),so create %d threads\n", num,num);
for(i = 0; i < num; i++)
{
id[i] = i;
if (pthread_create(&tid, NULL, (void *)myfunWithMultiThread, (void *)&id[i]) != 0)
{
fprintf(stderr, "thread create failed\n");
return -1;
}
}
pthread_join(tid, NULL);
return 0;
}
运行结果:System has 8 processor(s),so create 8 threads
thread 1188759312 is running in processor 5
Original setting is in processor 5
thread 1205544720 is running in processor 3
Original setting is in processor 3
thread 1197152016 is running in processor 4
Original setting is in processor 4
thread 1230722832 is running in processor 0
Original setting is in processor 0
thread 1213937424 is running in processor 2
Original setting is in processor 2
thread 1222330128 is running in processor 1
Original setting is in processor 1
thread 1180366608 is running in processor 6
Original setting is in processor 6
thread 1171973904 is running in processor 7
Original setting is in processor 7
2.2 不绑定测试代码
System has 8 processor(s),so create 8 threads
thread -196520176 is running in processor 0
thread -196520176 is running in processor 1
thread -196520176 is running in processor 2
thread -196520176 is running in processor 3
thread -196520176 is running in processor 4
thread -196520176 is running in processor 5
thread -196520176 is running in processor 6
thread -196520176 is running in processor 7
thread -221698288 is running in processor 0
thread -221698288 is running in processor 1
thread -221698288 is running in processor 2
thread -221698288 is running in processor 3
thread -221698288 is running in processor 4
thread -221698288 is running in processor 5
thread -221698288 is running in processor 6
thread -221698288 is running in processor 7
thread -213305584 is running in processor 0
thread -213305584 is running in processor 1
thread -213305584 is running in processor 2
thread -213305584 is running in processor 3
thread -213305584 is running in processor 4
thread -213305584 is running in processor 5
thread -213305584 is running in processor 6
thread -213305584 is running in processor 7
thread -230090992 is running in processor 0
thread -230090992 is running in processor 1
thread -230090992 is running in processor 2
thread -204912880 is running in processor 0
thread -204912880 is running in processor 1
thread -204912880 is running in processor 2
thread -238483696 is running in processor 0
thread -230090992 is running in processor 3
由以上结果可以看出,linux是不会默认对线程进行和CPU进行绑定的,如果有需要必须自己显式的调用函数绑定。
3. 结论
线程与CPU进行绑定可以减少线程在不同核之间切换的开销,但是要遵循一定的规则,并不是每个线程都与特定CPU绑定效率高。一般来说计算密集型的程序与CPU绑定与不绑定相比效果要好得多,但对于IO密集型的程序来说,影响不是太大。