【发布时间】:2022-01-01 23:04:06
【问题描述】:
我在一台装有 Apple M1 的笔记本电脑中,它有 4 个内核。我有一个问题可以通过动态生成数百万线程来并行解决。由于pthread_create 的开销很大,因此我通过在后台保留3 个线程来避免它。这些线程等待任务到达:
void *worker(void *arg) {
u64 tid = (u64)arg;
// Loops until the main thread signals work is complete
while (!atomic_load(&done)) {
// If there is a new task for this worker...
if (atomic_load(&workers[tid].stat) == WORKER_NEW_TASK) {
// Execute it
execute_task(&workers[tid]);
}
}
return 0;
}
这些线程使用pthread_create 生成一次:
pthread_create(&workers[tid].thread, NULL, &normal_thread, (void*)tid)
任何时候我需要完成一个新任务,而不是再次调用pthread_create,我只是选择一个空闲的工作人员并将任务发送给它:
workers[tid].stat = WORKER_NEW_TASK
workers[tid].task = ...
问题是:出于某种原因,将这 3 个线程留在后台会使我的主线程慢 25%。由于我的 CPU 有 4 个内核,我希望这 3 个线程根本不会影响主线程。
为什么后台线程会拖慢主线程?我做错什么了吗? while (!atomic_load(&done)) 循环是否消耗大量 CPU 资源?
【问题讨论】:
-
您假设调度程序会将您的四个线程上的处理器亲和性设置为仅在选定的内核上运行。调度程序可以/将把活动推送到它想要的任何核心,核心交换机并不便宜(也不免费)。至于做错什么,除非您有非常充分的理由在原子标志上自旋循环,否则您最好使用 cvar+mutex 对来管理为您的队列服务的工作人员。
-
我预计这个问题会被否决(因为根据我目前的知识,我真的无法让它变得更好),但我仍然很高兴我问了这个问题。 @WhozCraig 感谢您的提示,我会研究这个方向。 “除非你有充分的理由在原子标志上旋转循环,否则使用 cvar+mutex 可能会更好” - 这不是你可以在互联网上轻松找到的知识,真的需要专业知识。这不就是 SO 的用途吗?
-
多线程编程确实是一个“专长”的东西,可以肯定的是,尤其是在 C 语言中。关于 POSIX 线程的学生文本将对如何实现 cvar+mutex 工作组系统有很好的参考. Butenhof 的“使用 POSIX 线程编程”是我 22 年前学习的文本(我的图书馆书架上仍然有该文本)。我相信网上也有很多例子;我只是更喜欢翻页而不是点击鼠标按钮。
-
嗯,俄亥俄州立大学目前正被犹他州淘汰,所以我现在有点心事重重。我会看看我是否可以在网上找到一些例子。毕竟,这是元旦。如果您真的想获得半运行的内容,则可以在配置线程时始终尝试推挤core affinity。正如我所说,就我个人而言,旋转等待的概念让我很反感,但有时需要它(例如无锁范例)。
-
@MaiaVictor 让您的线程以阻塞方式等待工作完成,而不是消耗 CPU 周期。您可以使用 pthread 条件变量来实现。
标签: c multithreading pthreads threadpool