线程调度和屈服

时间:2013-03-08 23:59:08

标签: c multithreading parallel-processing pthreads scheduling

如果我在四核上运行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)不是中断驱动的,并且条件变量在此上下文中是无用的。我想在输入线程中做的是检查一次条件,并放弃它的时间片。如果有足够的内核来运行所有线程,则输入线程将在其自己的内核上运行。如果不是,它将运行最小数量的检查,即每个时间片一次。我希望我足够清楚。

2 个答案:

答案 0 :(得分:1)

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

请参阅示例this SO question

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

我认为一些评论者已经对您的应用程序设计发表了一些合理的担忧,您可能需要考虑扩展这些对话,以确保您头脑中的设计能够真正有效地实现您想要的最终目标实现。

答案 1 :(得分:1)

嗯,MPI_recv声称要阻止,除非你做一些具体的改变。 MPI的底层通信基础设施很复杂,我不知道“阻塞”是否扩展到等待调用select()的网络套接字。你有点说它没有,我可以相信MPI的复杂性。

MPI的内部成员

因此,如果阻塞模式下的MPI_recv不可避免地涉及轮询,则需要确切地确定下面的库正在做什么。希望这是一个明智的民意调查(即涉及纳米睡眠()的调查。你可以查看那个(eek)的Open MPI源代码,或者使用this和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时间比,你可能会因为简单的源代码而处于低效状态。

相关问题