实时调度类

按照POSIX标准的强制要求,除了“普通”进程之外, Linux还支持两种实时调度类。调度器结构使得实时进程可以平滑地集成到内核中,而无需修改核心调度器,这显然是调度类带来的好处。

现在比较适合于回想一些很久以前讨论过的事实。实时进程的特点在于其优先级比普通进程高,对应地,其static_prio值总是比普通进程低,如图2-14所示。 rt_task宏通过检查其优先级来证实给定进程是否是实时进程,而task_has_rt_policy则检测进程是否关联到实时调度策略。

1. 性质

实时进程与普通进程有一个根本的不同之处:如果系统中有一个实时进程且可运行,那么调度器总是会选中它运行,除非有另一个优先级更高的实时进程。

现有的两种实时类,不同之处如下所示。

  • 循环进程(SCHED_RR)有时间片,其值在进程运行时会减少,就像是普通进程。在所有的时间段都到期后,则该值重置为初始值,而进程则置于队列的末尾。这确保了在有几个优先级相同的SCHED_RR进程的情况下,它们总是依次执行。
  • 先进先出进程(SCHED_FIFO)没有时间片,在被调度器选择执行后,可以运行任意长时间。

很明显,如果实时进程编写得比较差,系统可能变得无法使用。只要写一个无限循环,循环体内不进入睡眠即可。在编写实时应用程序时,应该多加小心。

1.2 数据结构

实时进程的调度类定义如下:

kernel/sched-rt.c

const struct sched_class rt_sched_class = {
.next = &fair_sched_class,
.enqueue_task = enqueue_task_rt,
.dequeue_task = dequeue_task_rt,
.yield_task = yield_task_rt,
.check_preempt_curr = check_preempt_curr_rt,
.pick_next_task = pick_next_task_rt,
.put_prev_task = put_prev_task_rt,
.set_curr_task = set_curr_task_rt,
.task_tick = task_tick_rt,
};

实时调度器类的实现比完全公平调度器简单。大约只需要250行代码,而CFS则需要1100行!

kernel/sched.c

struct rq {
...
t_rq rt;
...
}

就绪队列非常简单,链表就足够了:

kernel/sched.c

struct rt_prio_array {
DECLARE_BITMAP(bitmap, MAX_RT_PRIO+1); /* 包含1比特用于间隔符 */
struct list_head queue[MAX_RT_PRIO];
};
struct rt_rq {
struct rt_prio_array active;
};

具有相同优先级的所有实时进程都保存在一个链表中,表头为active.queue[prio],而active.bitmap位图中的每个比特位对应于一个链表,凡包含了进程的链表,对应的比特位则置位。如果链表中没有进程,则对应的比特位不置位。图2-23说明了具体情形。

实时调度器类中对应于update_cur的是update_curr_rt,该函数将当前进程在CPU上执行花费的时间记录在sum_exec_runtime中。所有计算的单位都是实际时间,不需要虚拟时间。这样就简化了很多。

3. 调度器操作

进程的入队和离队都比较简单。只需以p->prio为索引访问queue数组queue[p->prio],即可获得正确的链表,将进程加入链表或从链表删除即可。如果队列中至少有一个进程,则将位图中对应的比特位置位;如果队列中没有进程,则清除位图中对应的比特位。请注意,新进程总是排列在每个链表的末尾。

两个比较有趣的操作分别是,如何选择下一个将要执行的进程,以及如何处理抢占。首先考虑pick_next_task_rt,该函数放置选择下一个将执行的进程。其代码流程图在图2-24给出。

sched_find_first_bit是一个标准函数,可以找到active.bitmap中第一个置位的比特位,这意味着高的实时优先级(对应于较低的内核优先级值),因此在较低的实时优先级之前处理。取出所选链表的第一个进程,并将se.exec_start设置为就绪队列的当前实际时钟值,即可。

周期调度的实现同样简单。SCHED_FIFO进程最容易处理。它们可以运行任意长的时间,而且必须使用yield系统调用将控制权显式传递给另一个进程:

kernel/sched.c

static void task_tick_rt(struct rq *rq, struct task_struct *p)
{
update_curr_rt(rq);
/*
* 循环进程需要一种特殊形式的时间片管理。
* 先进先出进程没有时间片。
*/
if (p->policy != SCHED_RR)
return;
...

如果当前进程是循环进程,则减少其时间片。在尚未超出时间段时,没什么可作的,进程可以继续执行。计数器归0后,其值重置为DEF_TIMESLICE,即100 * HZ / 1000,亦即100毫秒。如果该进程不是链表中唯一的进程,则重新排队到末尾。通过用set_tsk_need_resched设置TIF_NEED_RESCHED标志,照常请求重调度:

为将进程转换为实时进程,必须使用sched_setscheduler系统调用。这里不详细讨论该函数了,因为它只执行了下列简单任务。

  • 使用deactivate_task将进程从当前队列移除。
  • 在task_struct中设置实时优先级和调度类。
  • 重新激活进程

如果进程此前不在任何就绪队列上,那么只需要设置调度类和新的优先级数值。停止进程活动和重激活则是不必要的。

要注意,只有具有root权限(或等价于CAP_SYS_NICE)的进程执行了sched_setscheduler系统调用,才能修改调度器类或优先级。否则,下列规则适用。

  • 调度类只能从SCHED_NORMAL改为SCHED_BATCH,或反过来。改为SCHED_FIFO是不可能的。
  • 只有目标进程的UID或EUID与调用者进程的EUID相同时,才能修改目标进程的优先级。此外,优先级只能降低,不能提升。

原文地址:https://www.cnblogs.com/linhaostudy/p/9978386.html

时间: 2024-11-08 19:30:36

实时调度类的相关文章

Linux进程管理 (7)实时调度

关键词:RT.preempt_count.RT patch. 除了CFS调度器之外,还包括重要的实时调度器,有两种RR和FIFO调度策略.本章只是一个简单的介绍. 更详细的介绍参考<Linux进程管理 (9)实时调度类分析,以及FIFO和RR对比实验>. 同时为了提高Linux的实时性,Linux社区还维护了realtime相关的补丁.这些补丁的介绍在<Linux实时补丁及其分析>. 1. 抢占内核 如果Linux内核不支持抢占,那么进程要么主动要求调度,如schedule()或者

操作系统精髓与设计--多处理器和实时调度

概述 对于多处理器调度,此处概述了多个处理器可能带来的问题和设计上的一些问题:对于实时调度,概述了两种调度方法:限时调度和速率单调调度. 1 多处理器调度 多处理器系统可以分为以下几类: 松耦合.分布式处理器.集群:有一系列相对自治的系统组成,每个处理器有自己的内存和I/O通道. 专门功能的处理器:I/O处理器时一个例子,此时有一个通用的主处理器,专门处理器受主处理器的控制,并给主处理器提供服务. 紧耦合多处理器:由一系列共享同一个内存并在操作系统完全控制的处理器组成,这里详细分析. 1.1 多

高性能 TCP Socket连接关闭释放集中调度类

/// <summary> /// Socket关闭调度类,此类提供了静态访问,但是此类可以实例化 /// </summary> /// <remarks> /// Socket连接关闭类 /// 3个队列 /// 1.shotdown 关闭队列 /// 步骤1 /// 2.close 队列 间隔2秒 /// 步骤2 /// 3.dispose 队列 间隔1秒 /// 步骤3 /// </remarks> public class CloseSoketDis

【原创】(六)Linux进程调度-实时调度器

背景 Read the fucking source code! --By 鲁迅 A picture is worth a thousand words. --By 高尔基 说明: Kernel版本:4.14 ARM64处理器,Contex-A53,双核 使用工具:Source Insight 3.5, Visio 1. 概述 在Linux内核中,实时进程总是比普通进程的优先级要高,实时进程的调度是由Real Time Scheduler(RT调度器)来管理,而普通进程由CFS调度器来管理. 实

Springmvc中配置Quartz使用,实现任务实时调度。

菜鸡的自我修炼,第一次接触quartz,做个记录.-------jstarseven 最近在项目中,第一次在springmvc中配置实用quartz,深刻的感受到quartz带来的方便,顺手做个记录. 简单介绍: Quartz 是个开源的作业调度框架,为在 Java 应用程序中进行作业调度提供了简单却强大的机制.Quartz 允许开发人员根据时间间隔(或天)来调度作业.它实现了作业和触发器的多对多关系,还能把多个作业与不同的触发器关联.整合了 Quartz 的应用程序可以重用来自不同事件的作业,

Linux进程上下文切换过程context_switch详解--Linux进程的管理与调度(二十一)【转】

转自:http://blog.csdn.net/gatieme/article/details/51872659 版权声明:本文为博主原创文章 && 转载请著名出处 @ http://blog.csdn.net/gatieme 目录(?)[-] 前景回顾 1 Linux的调度器组成 2 调度工作 进程上下文 1 进程上下文的概念 2 上下文切换 context_switch进程上下文切换 1 context_switch完全注释 2 prepare_arch_switch切换前的准备工作

Linux进程调度器的设计--Linux进程的管理与调度(十七)

日期 内核版本 架构 作者 GitHub CSDN 2016-06-14 Linux-4.6 X86 & arm gatieme LinuxDeviceDrivers Linux进程管理与调度 前景回顾 进程调度 内存中保存了对每个进程的唯一描述, 并通过若干结构与其他进程连接起来. 调度器面对的情形就是这样, 其任务是在程序之间共享CPU时间, 创造并行执行的错觉, 该任务分为两个不同的部分, 其中一个涉及调度策略, 另外一个涉及上下文切换. 内核必须提供一种方法, 在各个进程之间尽可能公平地

Linux核心调度器之周期性调度器scheduler_tick--Linux进程的管理与调度(十八)

日期 内核版本 架构 作者 GitHub CSDN 2016-6-29 Linux-4.6 X86 & arm gatieme LinuxDeviceDrivers Linux进程管理与调度 我们前面提到linux有两种方法激活调度器:核心调度器和 一种是直接的, 比如进程打算睡眠或出于其他原因放弃CPU 另一种是通过周期性的机制, 以固定的频率运行, 不时的检测是否有必要 因而内核提供了两个调度器主调度器,周期性调度器,分别实现如上工作, 两者合在一起就组成了核心调度器(core schedu

操作系统精髓与设计原理------调度概述

前言:操作系统必须为多个进程之间可能有竞争关系的请求分配计算机资源.对处理器而言,可分配的资源是处理器上的执行时间,分配的途径是"调度".调度功能必须设计成可以满足多个目标,包括公平.任何进程都不会产生饥饿.有效的使用处理器时间以及较低的开销,此外,调度中还需要考量优先级和实时期限方面.从根本上说,调度是属于队列管理,用来在排队环境中减少延迟和优化性能.(只记录了一些基本概念,细节还要回顾书) 一.调度类型 长程调度:决定加入到待执行的进程池中. 中程调度:决定加入到部分或全部在内存中