Linux(内核剖析):12---进程调度之与调度相关的系统调用

一身转战三千里,一剑曾百万师。这篇文章主要讲述Linux(内核剖析):12---进程调度之与调度相关的系统调用相关的知识,希望能为你提供帮助。

  • Linux提供了一个系统调用族,用于管理与调度程序相关的参数。这些系统调用可以用来操作和处理进程优先级、调度策略及处理器绑定,同时还提供了显式地将处理器交给其他进程的机制
  • 下标列举了这些系统调用,我们会在后面介绍系统调用的时候介绍这些函数
【Linux(内核剖析):12---进程调度之与调度相关的系统调用】
Linux(内核剖析):12---进程调度之与调度相关的系统调用

文章图片

一、与调度策略和优先级相关的系统调用
  • sched_setscheduler()、sched_getscheduler():
    • 分別用于设置和获取进程的调度策略和实时优先级。与其他的系统调用相似,它们的实现也是由许多参数检査、初始化和清理构成的。其实最重要的工作在于读取或改写进程task_struct的policy和rt_priority
  • sched_setparam()和sched_getparam():
    • 分别用于设置和获取进程的实时优先级。这两个系统调用获取封装在sched_param特殊结构体的rt_priority中
  • sched_get_priority_max()和sched_get_priority_min():
    • 分别用于返回给盯调度策略的最大和最小优先级。实时调度策略的最大优先级是MAC_USER_RT_PRIO减1,最小优先级等于1
  • nice():
    • 对于一个普通的进程,nice()函数可以将给定进程的静态优先级增加一个给定的量。只有超级用户才能在调用它时使用负值,从而提高进程的优先级。
    • nice()函数会调用内核的set_user_nice()函数,这个函数会设置进程的task_struct的static_prio和prio值
二、与处理器绑定有关的系统调用
  • 处理器绑定机制:Linux调度程序提供强制的处理器绑定(processor affinity)机制。也就是说,虽然它尽力通过一种软的(或者说自然的)亲和性试图使进程尽量在同一个处理器上运行,但它也允许用户强制指定“这个进程无论如何都必须在这些处理器上运行”
  • cpus_allowed标志:
    • 处理器绑定相关的机制与task_struct结构的cpus_allowed这个位掩码标志有关
    • 该掩码标志的每一位对应一个系统可用的处理器。默认情况下,所有的位都被设置,进程可以在系统中所有可用的处理器上执行
  • sched_setaffinity()、sched_getaffinity():
    • 用户可以通过sched_setaffinity()设置不同的一个或几个位组合的位掩码,而调用sched_getaffinity()则返回当前的cpus_allowed位掩码
  • 强制处理器绑定的原理:
    • 内核提供的强制处理器绑定的方法很简单
    • 首先,当处理进行第一次创建时,它继承了其父进程的相关掩码。由于父进程运行在指定处理器上,子进程也运行在相应处理器上
    • 其次,当处理器绑定关系改变时,内核会采用“移植线程”把任务推到合法的处理器上
    • 最后,加载平衡器只把任务拉到允许的处理器上,因此,进程只运行在指定处理器上,对处理器的指定是由该进程描述符的cpus_allowed域设置的
三、放弃处理器时间(yield()、sched_yield())
  • Linux过sched_yield()系统调用,提供了一种让进程显式地将处理器时间让给其他等待执行进程的机制
  • 原理:
    • 它是通过将进程从活动队列中(因为进程正在执行,所以它肯定位于此队列当中)移到过期队列中实现的
    • 由此产生的效果不仅抢占了该进程并将其放入优先级队列的最后面,还将其放入过期队列中——这样能确保在一段时间内它都不会再被执行了
    • 由于实时进程不会过期,所以属于例外。它们只被移动到其优先级队列的最后面(不会放到过期队列中)
  • 在Linux的早期版本中,sched_yield()的语义有所不同,进程只会被放置到优先级队列的末尾,放弃的时间往往不会太长。现在,应用程序甚至内核代码在调用sched_yield()前,应该仔细虑是否真的希望放弃处理器时间
  • 内核代码为了方便,可以直接调用yield(),先要确定给定进程确实处于可执行状态,然后再调用sched_yield()。用户空间的应用程序直接使用sched_yield()系统调用就可以了

    推荐阅读