0

如果我在四核上运行 4 个工作线程和 1 个 I/O 线程,则其中一个线程将与另一个线程重叠。我如何确保输入线程总是与另一个线程重叠,以便我可以 sched_yield() 将其当前时间片放弃给另一个线程。如果是重叠的两个工作线程,输入线程上的yield不会有任何影响,对吧?sched_yield 会从不同的核心带来另一个线程吗?

#include <sched.h>
#include <pthread.h>
void test(void*) {
   while(1) {}
}
int main (void) {
   pthread_t t; 
   for(int i = 0;i < 4;i++)
       pthread_create(&t,0,(void*(*)(void*))test,0); //workers
   while (1) {
       sched_yield(); //input thread
   }
   return 0;
}

编辑 输入线程需要轮询传入的消息。我正在使用的库(MPI)不是中断驱动的,在这种情况下条件变量是无用的。我想在输入线程中做的是检查一次条件,然后放弃它的时间片。如果有足够的核心来运行所有线程,则输入线程将在自己的核心上运行。如果不是,它将运行最少数量的检查,即每个时间片一次。我希望我足够清楚。

4

2 回答 2

1

嗯,MPI_recv 声称是阻塞的,除非你做一些特定的事情来改变它。MPI 的底层通信基础设施很复杂,我不知道“阻塞”是否延伸到通过调用 select() 等待网络套接字。你有点说它没有,考虑到 MPI 的复杂性,我完全可以相信这一点。

MPI 的内部结构

因此,如果 MPI_recv 在阻塞模式下不可避免地涉及轮询,则需要弄清楚下面的库正在做什么。希望这是一个明智的民意调查(即涉及调用 nanosleep() 的民意调查)。您可以查看该 (eek) 的 Open MPI 源代码,或者使用和 GTKWave 以一种很好的图形方式查看它的调度行为(我假设您在 Linux 上)。

如果它在轮询循环中休眠,那么 Linux 内核的版本很重要。更现代的内核(可能需要 PREEMPT_RT 补丁集 - 恐怕我不记得了)即使在短时间内也会执行适当的计时器驱动的取消调度睡眠,因此不会占用 CPU 时间。较旧的实现只会进入一个繁忙的循环以进行短暂的睡眠,这对您没有好处。

如果它根本不睡觉,那就更难了。您必须在非阻塞模式下使用 MPI 并自己进行轮询/睡眠。

线程优先级

一旦您通过睡眠轮询您的或 MPI 的代码,您就可以依靠使用线程优先级和操作系统调度程序来解决问题。一般来说,将 I/O 线程置于比工作线程更高的优先级是一个好主意。它可以防止 I/O 另一端的进程被抢占 I/O 线程的工作线程阻塞。由于这个原因 sched_yield() 不是一个好主意,因为调度程序不会让你的线程进入睡眠状态。

线程亲和力

一般来说,我不会为此烦恼,至少现在还不会。你有 5 个线程和 4 个内核;这些线程之一将永远令人失望。如果您让内核尽可能地解决问题,那么只要您控制了轮询(如上所述),您应该没问题。

- 编辑 -

我已经去看看 MPI 和线程,并重新发现了我不喜欢它的原因。MPI 为进程相互通信,每个进程都有一个“等级”。虽然 MPI 是/可以是线程安全的,但线程本身并没有自己的等级。所以 MPI 不能在线程之间进行交互。在当今多核设备的时代,这是 MPI 的一个弱点。

但是,您可以有 4 个单独的进程并且没有 I/O 线程。就复制、移动和存储的数据量而言,这可能不是最佳的(它将是网络流量的 4 倍,使用的内存的 4 倍等)。但是,如果您有足够大的计算时间:I/O 时间比率,那么为了简单的源代码,您可能能够忍受这种低效率。

于 2013-03-09T08:38:37.243 回答
1

您正在寻找的 Googleable 短语是“CPU 亲和力”。

参见例如这个 SO question

确保每个工作线程在不同的核心上运行将实现您的既定目标。

我认为许多评论者对您的应用程序的设计提出了一些合理的担忧,您可能需要考虑扩展这些对话,以确保您脑海中的设计实际上能够有效地实现您想要实现的最终目标。

于 2013-03-09T03:45:26.180 回答