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