Linux 如何绑定指定线程在某个固定CPU上
gcc version:5.4.0
Linux version: 4.4.0
之所以先说明版本,因为不同版本上很有可能有不同的问题。
绑定的方法主要是靠 setaffinity / getaffinity 一组方法来做的,其中有
#define _GNU_SOURCE
#include <sched.h>
int sched_setaffinity(pid_t pid, size_t cpusetsize, const cpu_set_t *mask);
int sched_getaffinity(pid_t pid, size_t cpusetsize, const cpu_set_t *mask);
#define _GNU_SOURCE
#include <pthread.h>
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, const cpu_set_t *cpuset);
其中的 CPU_SET 可以直接看 manual,但是我把它的一些使用放在下面:
#define _GNU_SOURCE
#include <sched.h>
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, cpu_set_t *set); // 尝试 \cpu 是否在 cpu_set 中
int CPU_COUNT(cpu_set_t *set); // 将 cpu_set 中设置的 cpu 数量返回
一个使用 affinity 方法的 demo code:
#include <stdio.h>
#include <stdlib.h>
//#define __USE_GNU
#define _GNU_SOURCE
#include <time.h>
#include <sched.h>
#include <pthread.h>
void mybind_cpu(int cpu_id)
{
cpu_set_t mask;
CPU_ZERO(&mask);
CPU_SET(cpu_id, &mask);
if (sched_setaffinity(0, sizeof(cpu_set_t), &mask) < 0) {
printf("Error: setaffinity()\n");
exit(0);
}
return ;
}
void test_thread(void* cpu_id) {
int cpuid = (int)(long)cpu_id;
mybind_cpu(cpuid);
printf("thread(%d) is running\n", (int)pthread_self());
return ;
}
int main(void)
{
int res;
void *thread_result;
pthread_t test_thread_ctrl[10];
int i = 0;
for (i = 0; i < 10; ++i) {
pthread_create(&(test_thread_ctrl[i]), NULL, (void*)test_thread, (void*)0);
}
for (i = 0; i < 10; ++i)
res = pthread_join(test_thread_ctrl[i], &thread_result);
(void)res;
return 0;
}
这样用 gcc 编译会报错,错误是
bind_cpu.c:(.text+0x30): undefined reference to `CPU_ZERO'
bind_cpu.c:(.text+0x4c): undefined reference to `CPU_SET'
collect2: error: ld returned 1 exit status
查看 sched.h 文件会发现 CPU_ZERO 定义为(xshell上的文本太难拷贝了,我还是直接截图算了):
那么再引入 __USE_GNU 宏,又会报错:
然后我直接把这个函数的定义给注释掉了,就ok了,最后成功运行。
说明一下,虽然 affinity 这个单词只是暗示函数会让 thread 保证对某些 CPU 有亲和性,但是实际的函数定义处,却可以看到这句注释:
当然,怎么理解就见仁见智了。
来自10分钟后的更新。。。
搜了一下,stackoverflow上有人提到了,__locale_t 这个类型在 xlocale.h 文件里,而这个文件只包含在 string.h 内,并且只有打开 __USE_XOPEN2K8 才能看见,因此改了一下前面的头文件 include,加上:
#define __USE_XOPEN2K8
#include <string.h>
果然大功告成了!!!不用作死去改 glibc 的头文件了。
Reference:
stackoverflow: https://stackoverflow.com/questions/24738059/c-error-locale-t-has-not-been-declared