【发布时间】:2018-08-17 10:16:42
【问题描述】:
我编写了一个小测试程序,它生成大量线程(在我的情况下,在具有 4 个内核的计算机上为 32 个线程)并使用 pthread_setaffinity_np 系统调用将它们全部固定到一个内核。
这些线程在循环中运行,它们通过标准输出报告sched_getcpu 调用的结果,然后休眠一小段时间。我想看到的是,操作系统如何严格遵守用户的线程固定设置(即使它们在我的情况下没有意义)。
所有线程报告都在我将它们固定到的核心上运行,这是我所期望的。
但是,我注意到,当程序运行时,所有 4 个内核的 cpu 利用率都在 100% 左右(通常在 0% 到 25% 之间)。有人能告诉我为什么会这样吗? 我本来希望固定核心上的利用率最大,而其他核心上的利用率可能会更高一些以进行补偿。
如有必要,我可以附加我的代码,但我认为它非常简单,因此并不是真正必要的。我在一台装有 Ubuntu 18.04 的相当旧的 PC 上进行了测试。
更新
#define _GNU_SOURCE
#include <assert.h>
#include <pthread.h>
#include <sched.h>
#include <stdio.h>
#include <unistd.h>
#define THREADS 32
#define PINNED 3
#define MINUTE 60
#define MILLISEC 1000
void thread_main(int id);
int main(int argc, char** argv) {
int i;
pthread_t pthreads[THREADS];
printf("%d threads will be pinned to cpu %d\n", THREADS, PINNED);
for (i = 0; i < THREADS; ++i) {
pthread_create(&pthreads[i], NULL, &thread_main, i);
}
sleep(MINUTE);
return 0;
}
void thread_main(int id) {
printf("thread %d: inititally running on cpu %d\n", id, sched_getcpu());
pthread_t pthread = pthread_self();
cpu_set_t cpu_set;
CPU_ZERO(&cpu_set);
CPU_SET(PINNED, &cpu_set);
assert(0 == pthread_setaffinity_np(pthread, sizeof(cpu_set_t), &cpu_set));
while (1) {
printf("thread %d: running on cpu %d\n", id, sched_getcpu());
//usleep(MILLISEC);
}
}
当我关闭所有后台活动时,利用率并不是 100%,但肯定会在很大程度上影响所有 4 个核心。
【问题讨论】:
-
我们需要查看代码,根据您的描述,这不应该发生,所以代码可能有错误。
-
看起来线程 printf 永远以 100% CPU 输出到标准输出?你让他们在哪里睡觉?如果您不这样做,还有什么可期待的?
-
我只注释掉了usleep进行测试,抱歉。我的问题是所有 CPU 都会出现峰值,尽管所有线程似乎只在一个 cpu 上运行。
-
你绝对应该不在
assert(/* here */)中放入any副作用的东西,因为当NDEBUG被定义时,你的assertions将被剥夺……逻辑也将被剥夺。我建议像int fubar = pthread_setaffinity_np(...); assert(!fubar);... -
如果您在伪终端中运行这些,那么另一个进程正在接收所有
printf输出并对其进行处理,这也需要 CPU 时间。该过程(您的终端,也可能是 Xorg)将大量出现在配置文件中。考虑到以图形方式呈现文本输出将比生成它的printf()占用更多 CPU。尝试运行您的测试过程,并将输出重定向到/dev/null。
标签: c linux multithreading pthreads affinity