本文结合 Linux 5.0.1 内核源码,浅析 Linux 进程管理中的完全公平调度器(CFS)工作原理。
1. 概述
完全公平调度器(Completely Fair Scheduler, CFS)自 Linux 内核 2.6.23 版本引入,作为替代传统调度器的默认进程调度算法,其设计目标是在所有可运行进程之间近似地实现理想的、无差别的公平处理器时间分配。
在多任务操作系统中,调度器 是内核的核心组件,负责在竞争性的进程之间高效、合理地分配有限的 CPU 时间资源。CFS 的提出,旨在克服先前调度算法(如 O(1) 调度器)在交互性、公平性及可扩展性方面的局限,它通过一种精妙的模型,确保每个进程能获得与其优先级相匹配的、近乎平等的 CPU 时间份额。
CFS 的实现基石是 虚拟运行时间(vruntime)。该指标并非简单的实际运行时间,而是一种经过进程优先级(权重)归一化处理后的度量。CFS 通过持续追踪每个进程的 vruntime,并始终选择 vruntime 最小的进程进行调度,以此在宏观上逼近所有进程 vruntime 同步增长的理想公平状态。
然而,在一个复杂的抢占式多任务环境中,vruntime 虽是调度决策的核心依据,但并非唯一因素。完整的调度行为还需综合考虑诸如处理器亲和性、负载均衡、中断与唤醒事件,以及更复杂的调度策略(如实时进程优先级)等多种因素的动态影响。
源码结构关系,请参考本章 核心结构 部分内容。
2. 虚拟运行时间调度
在 Linux 的完全公平调度器(CFS)设计中,每个 CPU 核心都拥有一个独立的调度域,其就绪队列使用一颗 红黑树 来组织。这棵树的排序关键字是每个进程的 “虚拟运行时间”(vruntime)。
核心机制与 vruntime 的作用:
- 排序依据:进程的 vruntime 值决定了它在红黑树中的位置,值越小,位置越靠左。
- 调度选择:调度器总是挑选 vruntime 最小的(即红黑树最左侧的)进程投入运行,这保证了最 “饥饿” 的进程能优先获得 CPU。
- 公平的实现:进程在 CPU 上运行后,其 vruntime 会随之增长,这使它逐渐向右移动,让位于其他 vruntime 更小的进程。高优先级进程(nice 值小 - 权重大)的 vruntime 增长更慢,因此能更频繁地被调度,从而获得更多的实际 CPU 时间。
2.1. vruntime
vruntime 它表示该进程在 CPU 上实际运行的时间经过加权后的结果。
调度器会优先选择 vruntime 值最小的进程运行,以确保每个进程的 vruntime 尽可能接近,从而实现公平的 CPU 时间分配。
1
| 新 vruntime = 旧 vruntime + 任务实际运行时间 × (nice 0 的权重 / 当前权重)
|
从时间计算公式可知:weight 权重越大 → vruntime 涨得越慢 → 更容易抢到 CPU。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
| // 进程任务结构
struct task_struct {
// 任务调度实体:包含任务在 CFS 调度器中的所有调度相关信息
struct sched_entity se;
...
};
// 负载权重结构:量化任务或调度组在 CPU 资源竞争中的优先级
struct load_weight {
...
// 权重值:决定任务在 CPU 时间分配中的相对比例
unsigned long weight;
...
};
// 调度实体:CFS 调度器管理的基本单位,可以是任务或任务组
struct sched_entity {
...
// 负载权重:该调度实体在 CPU 竞争中的重要程度
struct load_weight load;
...
// 虚拟运行时间
u64 vruntime;
...
// 当前任务时间片的开始时间
u64 exec_start;
...
};
|
2.2. 红黑树管理 vruntime
在 CFS 调度器中,所有可运行任务都作为调度实体按虚拟运行时间(vruntime)组织在红黑树中。
该红黑树通过运行队列的 rq.cfs.tasks_timeline 字段进行管理。
系统在每次调度时,从红黑树中获取最左侧节点(即 vruntime 最小的调度实体)进行调度。
这意味着任务的 vruntime 值越小,其调度优先级越高,越有可能获得 CPU 时间。
下图红黑树最左子树节点数值是 1。
图片来源:红黑树维基百科
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
| // CPU 运行队列
struct rq {
...
// 完全公平调度器
struct cfs_rq cfs;
...
};
// 完全公平调度运行队列(任务就绪队列)
struct cfs_rq {
// 左端缓存任务节点红黑树
struct rb_root_cached tasks_timeline;
...
};
// 进程任务结构
struct task_struct {
// 任务调度实体
struct sched_entity se;
...
};
// 左端缓存红黑树
struct rb_root_cached {
// 根节点
struct rb_root rb_root;
// 缓存红黑树最左节点(优化查找 leftmost 节点算法)
struct rb_node *rb_leftmost;
};
// 任务调度实体:CFS 调度器管理的基本单位,可以是任务或任务组
struct sched_entity {
...
// 进程任务红黑树节点
struct rb_node run_node;
...
// 虚拟运行时间
u64 vruntime;
...
};
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
| // 比较两个调度实体的 vruntime 大小
static inline int entity_before(struct sched_entity *a, struct sched_entity *b) {
return (s64)(a->vruntime - b->vruntime) < 0;
}
// 将调度实体插入 CFS 运行队列的红黑树中
static void __enqueue_entity(struct cfs_rq *cfs_rq, struct sched_entity *se) {
// 从红黑树根节点开始遍历,link指向当前检查的节点指针位置
struct rb_node **link = &cfs_rq->tasks_timeline.rb_root.rb_node;
struct rb_node *parent = NULL;
struct sched_entity *entry;
// 标记新节点是否将成为最左节点(vruntime 最小)
bool leftmost = true;
// 在红黑树中寻找合适的插入位置
while (*link) {
parent = *link;
// 通过 rb_entry 宏从 rb_node 获取包含它的 sched_entity 结构
entry = rb_entry(parent, struct sched_entity, run_node);
// 比较新实体与当前节点的 vruntime 大小
// 注意:不处理键值冲突,相同 vruntime 的节点放在右子树
if (entity_before(se, entry)) {
// 新实体 vruntime 更小,向左子树继续查找
link = &parent->rb_left;
} else {
// 新实体 vruntime 更大或相等,向右子树继续查找
link = &parent->rb_right;
// 向右查找意味着不会是新的最左节点
leftmost = false;
}
}
// 将新节点链接到找到的父节点下
rb_link_node(&se->run_node, parent, link);
// 调整红黑树颜色属性以保持平衡,并更新缓存的最左节点
rb_insert_color_cached(&se->run_node, &cfs_rq->tasks_timeline, leftmost);
}
|
2.3. vruntime 统计
- 更新当前运行任务的 vruntime:update_curr 。系统任何可能影响任务运行时间计算的时刻都会调用 update_curr,确保 vruntime 的实时性和准确性,为公平调度提供可靠的时间基准。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
| static void update_curr(struct cfs_rq *cfs_rq) {
// 当前运行的调度实体
struct sched_entity *curr = cfs_rq->curr;
// 获取当前 CPU 的 clock_task(仅统计任务执行时间,不含中断)。
// 类似"全局时钟",但仅统计任务执行时间(去除了中断干扰)
u64 now = rq_clock_task(rq_of(cfs_rq));
// 任务执行时间增量
u64 delta_exec;
...
// 计算自上次更新后的执行时间
delta_exec = now - curr->exec_start;
...
// 更新本次调度的起始时间
curr->exec_start = now;
...
// 根据任务的权重(weight)计算加权后的虚拟时间
// 高优先级任务(weight 大) → vruntime 增长慢 → 更容易被调度。
curr->vruntime += calc_delta_fair(delta_exec, curr);
...
}
|
1
2
3
4
5
6
7
8
9
| static inline u64 calc_delta_fair(u64 delta, struct sched_entity *se) {
// 计算负载权重不为 0 的时间增量
// NICE_0_LOAD:优先级为 0 时的负载权重
if (unlikely(se->load.weight != NICE_0_LOAD)) {
// 根据任务权重调整时间增量
delta = __calc_delta(delta, NICE_0_LOAD, &se->load);
}
return delta;
}
|
2.4. 进程任务调度
调度函数(__schedule)从当前 CPU 的任务就绪队列 cfs_rq 中取出一个合适的任务进行调度。
__schedule -> cur cpu -> rq -> cfs_rq-> pick_next_task -> fair_sched_class -> pick_next_task_fair -> context_switch(rq, prev, next)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
| // 每 CPU 运行队列管理结构
struct rq {
...
// 完全公平调度器
struct cfs_rq cfs;
...
// 调度类
const struct sched_class* sched_class;
...
};
// 任务就绪队列 - 完全公平调度器(CFS)运行队列结构
struct cfs_rq {
// 按 vruntime 排序的任务红黑树,缓存最左节点以优化访问
struct rb_root_cached tasks_timeline;
...
};
// 进程任务结构
struct task_struct {
// 任务调度实体
struct sched_entity se;
...
};
// 任务调度实体
struct sched_entity {
...
// 进程任务红黑树节点
struct rb_node run_node;
...
};
// 调度类
struct sched_class {
...
// 选择下一个任务的函数指针
struct task_struct *(*pick_next_task)(
struct rq *rq, struct task_struct *prev, struct rq_flags *rf);
...
};
// 完全公平调度器
const struct sched_class fair_sched_class = {
...
.pick_next_task = pick_next_task_fair,
...
};
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
| // 核心调度函数:负责选择下一个运行任务并执行上下文切换
static void __sched notrace __schedule(bool preempt) {
struct task_struct *prev, *next;
// 当前CPU的运行队列指针
struct rq *rq;
int cpu;
// 获取当前 CPU ID
cpu = smp_processor_id();
// 获取当前 CPU 对应的运行队列
rq = cpu_rq(cpu);
// 当前正在运行的任务
prev = rq->curr;
...
// 从运行队列中选择下一个要运行的任务
next = pick_next_task(rq, prev, &rf);
...
// 只有当任务切换确实发生时才执行上下文切换
if (likely(prev != next)) {
...
// 更新运行队列的当前任务指针
rq->curr = next;
...
// 执行任务上下文切换:保存 prev 上下文,加载 next 上下文
rq = context_switch(rq, prev, next, &rf);
}
...
}
|
1
2
3
4
5
6
7
8
9
10
11
12
13
| // 进程/线程创建时根据优先级绑定的调度方式
int sched_fork(unsigned long clone_flags, struct task_struct *p) {
...
if (dl_prio(p->prio)) {
return -EAGAIN;
} else if (rt_prio(p->prio)) {
p->sched_class = &rt_sched_class;
} else {
// 普通优先级进程使用完全公平调度器调度
p->sched_class = &fair_sched_class;
}
...
}
|
- 选择合适的调度器,从已选的调度器中获取下一个合适的运行任务。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
| static inline struct task_struct *
pick_next_task(struct rq *rq, struct task_struct *prev, struct rq_flags *rf) {
const struct sched_class *class;
struct task_struct *p;
// 优化:如果所有任务都在公平调度类中,可以直接调用公平调度函数
// 但前提是前一个任务不是更高调度级别的任务,否则可能失去从其他CPU拉取任务的机会
if (likely((prev->sched_class == &idle_sched_class ||
prev->sched_class == &fair_sched_class) &&
rq->nr_running == rq->cfs.h_nr_running)) {
// 直接从公平调度类中选择下一个任务
p = fair_sched_class.pick_next_task(rq, prev, rf);
// 如果返回 RETRY_TASK,表示需要重新选择,跳转到 again 标签
if (unlikely(p == RETRY_TASK))
goto again;
// 假设公平调度类的下一个是空闲调度类
// 如果没有可运行的公平任务,选择空闲任务
if (unlikely(!p))
p = idle_sched_class.pick_next_task(rq, prev, rf);
return p;
}
// 上面逻辑找不到合适任务时,按调度类优先级遍历
again:
// 按优先级从高到低遍历所有调度类
for_each_class(class) {
p = class->pick_next_task(rq, prev, rf);
if (p) {
// 如果返回 RETRY_TASK,重新开始遍历
if (unlikely(p == RETRY_TASK))
goto again;
return p;
}
}
...
}
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
| // CFS 调度器选择下一个任务的实现
static struct task_struct *
pick_next_task_fair(struct rq *rq, struct task_struct *prev, struct rq_flags *rf) {
// 获取 CFS 运行队列
struct cfs_rq *cfs_rq = &rq->cfs;
struct sched_entity *se;
struct task_struct *p;
...
// 当前正在运行的调度实体
struct sched_entity *curr = cfs_rq->curr;
...
// 从 CFS 红黑树中选择 vruntime 最小的下一个调度实体
se = pick_next_entity(cfs_rq, curr);
// 从调度实体转换为任务结构
p = task_of(se);
...
struct sched_entity *pse = &prev->se;
// 将当前任务重新放回运行队列(更新状态和位置)
put_prev_entity(cfs_rq, pse);
// 将选择的下一个任务从运行队列中取出,准备投入运行
set_next_entity(cfs_rq, se);
...
return p;
}
|
3. 核心结构
为了进一步理解 CFS 的调度源码,下面简单地梳理一下相关的数据结构关系。
3.1. 调度结构关系

| 结构 |
描述 |
| rq |
即通用的运行队列,系统中的每个 CPU 都配备一个对应的 rq 实例。其主要职责是管理该 CPU 上所有处于可运行状态的任务。rq 结构体内部包含了不同调度类的运行队列,像 CFS 运行队列(cfs_rq)、实时运行队列(rt_rq)以及限期调度器运行队列(dl_rq)等。同时,它还保存了一些与调度相关的统计信息,如可运行任务的数量(nr_running)、CPU 负载等,这些信息有助于调度器进行负载均衡和调度决策。 |
| cfs_rq |
属于 CFS 调度器的运行队列,CFS 调度器是 Linux 内核默认的普通任务调度器,其设计目标是让每个进程公平地获取 CPU 时间。cfs_rq 运用红黑树来组织可运行的调度实体,红黑树的节点按照调度实体的虚拟运行时间进行排序,虚拟运行时间越小的调度实体越靠近树的左侧。这样,调度器可以高效地找到下一个应该运行的调度实体,实现公平调度。 |
| task_struct |
Linux 内核里表征进程或线程的核心数据结构,它涵盖了进程全方位的状态信息。具体包括进程的唯一标识符(PID)、调度优先级(用于决定进程获取 CPU 资源的先后顺序)、内存管理信息(如页表、内存映射等)、文件描述符表(记录进程打开的文件)、信号处理信息(进程如何响应各种信号)以及进程的状态(如运行、睡眠、停止等)。这些信息使得内核能够全面管理和控制进程的生命周期和行为。 |
| sched_entity |
代表调度实体,是调度器实施调度操作的基本单元。在常规情形下,一个进程对应一个调度实体;但在组调度的场景中,一个进程可能会关联多个调度实体。调度实体存储了与调度相关的关键信息,例如虚拟运行时间(vruntime,在 CFS 调度器中用于衡量进程已使用的 CPU 时间)、调度优先级等。调度器依据这些信息来决定哪个调度实体能够获得 CPU 资源。 |
| sched_class |
调度器类的抽象定义,它定义了一套调度器操作的接口,不同的调度策略可以通过实现这些接口来完成特定的调度任务。内核中存在多种调度器类,如 CFS 调度器类、实时调度器类等。sched_class 结构体包含了一系列函数指针,用于实现任务的入队(enqueue_task)、出队(dequeue_task)、选择下一个任务(pick_next_task)、检查抢占(check_preempt_curr)等操作。不同的调度器类通过实现这些函数来体现各自的调度策略,例如实时调度器会优先调度实时任务,而 CFS 调度器则侧重于公平调度普通任务。 |
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
| // 运行队列
struct rq {
...
// 完全公平调度器
struct cfs_rq cfs;
...
// 调度类
const struct sched_class* sched_class;
...
};
// 完全公平调度器运行队列
struct cfs_rq {
// 红黑树
struct rb_root_cached tasks_timeline;
...
};
// 调度实体
struct sched_entity {
// 红黑树节点
struct rb_node run_node;
...
};
// 进程/线程结构
struct task_struct {
...
// 调度实体
struct sched_entity se;
...
// 调度类
const struct sched_class *sched_class;
...
};
// 调度类
struct sched_class {
...
// 任务入队
void (*enqueue_task) (struct rq *rq, struct task_struct *p, int flags);
// 任务出队
void (*dequeue_task) (struct rq *rq, struct task_struct *p, int flags);
...
};
// 完全公平调度类实例
const struct sched_class fair_sched_class = {
...
.enqueue_task = enqueue_task_fair,
.dequeue_task = dequeue_task_fair,
...
};
|
3.2. 结构描述
3.2.1. 运行队列 rq
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
| // 声明每 CPU 运行队列变量,缓存行对齐以避免伪共享
// 每个 CPU 拥有独立的运行队列,消除锁竞争,提升缓存局部性
DECLARE_PER_CPU_SHARED_ALIGNED(struct rq, runqueues);
// CPU运行队列管理结构
struct rq {
// 就绪队列中可运行任务的总数(所有调度类)
unsigned int nr_running;
// 完全公平调度器(CFS)运行队列,管理普通进程
struct cfs_rq cfs;
// 当前正在此CPU上运行的任务指针
struct task_struct *curr;
// 任务时钟:记录 CPU 真正用于执行任务的时间
// 排除中断处理、空闲时间、管理开销等
// 更新时机:
// - 任务切换时(context_switch)
// - 调度器时钟中断时(scheduler_tick)
u64 clock_task;
};
|
3.2.2. 完全公平调度运行队列 cfs_rq
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
| // 任务或者调度组的负载权重信息
struct load_weight {
// 负载权重
// 体现了任务或者调度组在竞争 CPU 资源时的优先级或者重要程度。
// 权重越大,该任务或者调度组在获取 CPU 时间上就更具优势。
// 在计算任务的 vruntime 增长速率时,高权重的任务 vruntime 增长得慢
unsigned long weight;
...
};
struct cfs_rq {
// 负载权重
struct load_weight load;
// 队列中所有可运行进程的权重累加结果
// 内核通过比较不同 CPU 上的 runnable_weight
// 判断负载是否均衡,决定是否迁移进程。
unsigned long runnable_weight;
// 队列中的可运行任务数量
unsigned int nr_running;
// 层级调度中的任务计数(支持 CGroup 嵌套)
unsigned int h_nr_running;
// cfs_rq 的总任务执行时间
// 记录该 cfs_rq 中所有任务累计的执行时间(单位:纳秒)
// 主要用于 负载统计和调度决策(如负载均衡)。
u64 exec_clock;
// 当前 cfs_rq 中所有任务的最小虚拟运行时间(vruntime)。
u64 min_vruntime;
// 红黑树根节点,按 vruntime 排序所有可运行任务
struct rb_root_cached tasks_timeline;
// 当前任务调度实体
struct sched_entity *curr;
struct sched_entity *next;
// cfs_rq 属于哪个 rq 运行队列
struct rq *rq;
...
};
// 红黑树缓存了最左子树的叶子节点,
// 使得获取最左子树叶子节点的时间复杂度为 O(1)
struct rb_root_cached {
struct rb_root rb_root;
struct rb_node *rb_leftmost;
};
|
3.2.3. 进程结构 task_struct
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
| // 进程状态
#define TASK_RUNNING 0x0000
#define TASK_INTERRUPTIBLE 0x0001
#define TASK_UNINTERRUPTIBLE 0x0002
#define __TASK_STOPPED 0x0004
#define __TASK_TRACED 0x0008
/* Used in tsk->exit_state: */
#define EXIT_DEAD 0x0010
#define EXIT_ZOMBIE 0x0020
// 进程结构
struct task_struct {
struct thread_info thread_info;
// 进程当前状态(例如:TASK_RUNNING)
volatile long state;
...
// 调度类
const struct sched_class* sched_class;
// 调度实体
struct sched_entity se;
// 任务是否在运行队列上
int on_rq;
// 调度器实际使用的动态优先级
int prio;
...
};
// thread information flags
#define TIF_SIGPENDING 2 /* signal pending */
#define TIF_NEED_RESCHED 3 /* rescheduling necessary */
struct thread_info {
unsigned long flags; /* low level flags */
u32 status; /* thread synchronous flags */
};
|
3.2.4. 调度实体 sched_entity
调度实体可以是 一个进程或者一个进程组,内核调度器会依据调度实体的相关信息来决定哪个进程可以获得 CPU 时间。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
| // 任务或者调度组的负载权重信息
struct load_weight {
// 调度实体的负载权重
unsigned long weight;
// 是 weight 的倒数,为提高调度计算效率,
// 避免在调度计算过程中频繁进行除法运算。
u32 inv_weight;
};
// 调度实体
struct sched_entity {
/* For load-balancing: */
struct load_weight load;
unsigned long runnable_weight;
// 红黑树节点
struct rb_node run_node;
struct list_head group_node;
// 任务是否在运行就绪队列上(等待调度)
unsigned int on_rq;
// 当前时间片的开始时间
u64 exec_start;
// 计算进程/线程的实际CPU占用时间
u64 sum_exec_runtime;
// CFS调度的进程/线程虚拟运行时间
u64 vruntime;
...
};
|
3.2.5. 调度器 sched_class
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
| struct sched_class {
// 指向另一个调度器类的指针,用于形成一个调度类链表
const struct sched_class *next;
// 将一个任务(进程或线程)加入到运行队列
void (*enqueue_task) (struct rq *rq, struct task_struct *p, int flags);
// 将一个任务从运行队列中移除
void (*dequeue_task) (struct rq *rq, struct task_struct *p, int flags);
// 当前正在运行的任务主动放弃CPU使用权
void (*yield_task) (struct rq *rq);
// 当前正在运行的任务主动让出CPU给指定的任务
bool (*yield_to_task) (struct rq *rq, struct task_struct *p, bool preempt);
// 检查是否需要对当前正在运行的任务进行抢占
void (*check_preempt_curr)(struct rq *rq, struct task_struct *p, int flags);
...
// 运行队列中选择下一个要运行的任务
struct task_struct * (*pick_next_task)(
struct rq *rq, struct task_struct *prev, struct rq_flags *rf);
// 处理之前正在运行的任务
void (*put_prev_task)(struct rq *rq, struct task_struct *p);
...
};
|
1
2
3
4
5
6
7
8
9
10
11
12
| // 完全公平调度器
const struct sched_class fair_sched_class = {
.next = &idle_sched_class,
.enqueue_task = enqueue_task_fair,
.dequeue_task = dequeue_task_fair,
.yield_task = yield_task_fair,
.yield_to_task = yield_to_task_fair,
.check_preempt_curr = check_preempt_wakeup,
.pick_next_task = pick_next_task_fair,
.put_prev_task = put_prev_task_fair,
...
};
|
1
2
3
4
5
6
7
8
9
10
11
12
13
| // 停止调度
// 通常用于系统关机或紧急情况(如CPU停止调度普通任务)
extern const struct sched_class stop_sched_class;
// 截止期调度:实时调度策略之一,基于截止时间进行任务调度,
// 硬实时任务(Hard Real-Time Task),
// 例如 音视频处理、机器人控制 等,对任务执行时间要求极高
extern const struct sched_class dl_sched_class;
// 实时调度:处理实时优先级任务(Real-Time Priority Tasks),优先级高于普通任务
extern const struct sched_class rt_sched_class;
// 完全公平调度:完全公平调度器,普通任务的主要调度类,负责大多数用户态进程的调度
extern const struct sched_class fair_sched_class;
// 空闲调度:用于CPU空闲时的任务,如果CPU没有任务可运行,就会进入空闲任务
extern const struct sched_class idle_sched_class;
|
4. 参考