Linux 进程调度器是一个进程吗? 还是一个策略
Linux 进程调度器(scheduler)不是一个进程,而是一套内核中的调度策略和相关代码的总称。
1. 调度器不是进程
- 调度器不是一个进程,它没有自己的 PID,也不会出现在 ps/top 等进程列表中。
- 它是内核代码的一部分,始终运行在内核空间,由内核负责调用和维护。
2. 调度器是什么?
- 调度器(scheduler)是一套算法和实现代码,决定了在任意时刻哪个进程/线程可以获得 CPU 运行。
- 它管理所有进程/线程的状态(就绪、运行、阻塞等),并根据优先级、调度策略等因素做出调度决策。
3. 调度器的实现位置
- 主要代码在 Linux 源码的
kernel/sched/
目录下,比如:-
core.c
(核心框架) -
fair.c
(CFS 完全公平调度器,普通进程用) -
rt.c
(实时调度器) -
deadline.c
(实时 deadline 调度器)
-
- 这些文件实现了不同的调度策略,比如 CFS、SCHED_FIFO、SCHED_RR、SCHED_DEADLINE 等。
4. 调度器的工作方式
- 每当需要切换进程(比如时间片用完、进程阻塞/唤醒、系统调用等),内核会调用调度器的相关函数(如
schedule()
)。 - 调度器会根据当前所有可运行进程的状态和优先级,选择下一个要运行的进程。
5. 调度策略的含义
-
调度策略是调度器内部支持的不同算法,比如:
- SCHED_OTHER(CFS,普通进程)
- SCHED_FIFO、SCHED_RR(实时进程)
- SCHED_DEADLINE(实时 deadline)
- 用户和程序可以通过系统调用(如
sched_setscheduler
)选择进程的调度策略。
6. 总结
Linux 进程调度器不是进程,而是内核中的一套调度算法和实现代码。它负责管理和切换所有进程的运行,是操作系统的核心组成部分。
Linux 系统运行过程中是有多个调度器在工作吗?
你的问题是:“Linux 系统运行过程中是有多个调度器在工作吗?”
简短回答:
不是有多个调度器在工作,而是有一个统一的调度框架,支持多种调度策略。所有 CPU(核)都用同一套调度器代码,但可以为不同进程/线程选择不同的调度策略。
1. 调度器的整体结构
- Linux 只有一个调度器框架(scheduler framework),它是内核的一部分,负责所有进程/线程的调度。
- 这个调度器框架支持多种调度策略(如 CFS、实时、deadline),这些策略在同一个调度器框架下协同工作。
2. 多核系统的调度
- 在多核(SMP)系统中,每个 CPU(核)都有自己的就绪队列(runqueue),但调度器的实现代码是同一套。
- 每个 CPU 都会独立运行调度器的调度逻辑(比如定时器中断触发 schedule()),但用的都是同样的调度器代码。
- 进程/线程可以在不同 CPU 之间迁移(load balance),这也是调度器负责的。
3. 多种调度策略的协作
-
调度器支持多种调度策略,比如:
- CFS(普通进程,SCHED_OTHER)
- 实时调度(SCHED_FIFO、SCHED_RR)
- Deadline 调度(SCHED_DEADLINE)
- 每个进程/线程可以选择自己的调度策略,调度器会根据优先级和策略统一管理。
- 例如,实时进程优先于普通进程,deadline 进程有自己的调度规则。
4. 源码结构
- 主要在
kernel/sched/
目录下,不同文件实现不同策略,但都属于同一个调度器框架。 - 例如:
-
fair.c
:CFS -
rt.c
:实时 -
deadline.c
:deadline -
core.c
:调度器核心框架
-
5. 总结
- Linux 只有一个调度器框架,但支持多种调度策略。
- 所有 CPU 都用同一套调度器代码,每个进程/线程可以选择不同的调度策略。
- 不是“多个调度器”并行工作,而是“一个调度器支持多种策略”。
一个进程是怎么选择不同的调度策略的
非常好的问题!
一个进程如何选择不同的调度策略?
这涉及到用户空间和内核空间的接口,以及调度器的实现。下面详细解答:
1. 什么是调度策略?
Linux 支持多种调度策略(policy),常见的有:
-
SCHED_OTHER
(也叫SCHED_NORMAL
,CFS,普通进程) -
SCHED_FIFO
(实时,先进先出) -
SCHED_RR
(实时,时间片轮转) -
SCHED_BATCH
(批处理) -
SCHED_IDLE
(空闲进程) -
SCHED_DEADLINE
(实时 deadline)
2. 进程如何选择/更改调度策略?
A. 通过系统调用
- 主要有两个相关系统调用:
-
sched_setscheduler(pid, policy, ¶m)
设置指定进程的调度策略和优先级 -
sched_setparam(pid, ¶m)
只设置优先级,不改变策略
-
示例代码:
#include <sched.h>
struct sched_param param;
param.sched_priority = 80; // 1~99 for real-time
sched_setscheduler(0, SCHED_FIFO, ¶m); // 把当前进程设置为实时FIFO策略
B. 通过命令行工具
-
chrt
命令可以在 shell 下设置进程的调度策略和优先级:
chrt -f -p 80 1234 # 把 PID 1234 设置为 SCHED_FIFO,优先级80
chrt -r 50 myprog # 以 SCHED_RR 策略、优先级50启动 myprog
-
nice
/renice
只能调整普通进程的 nice 值,不能切换到实时策略。
3. 新进程的策略继承
-
fork()
出来的子进程会继承父进程的调度策略和优先级。 -
exec()
不会改变调度策略。
4. 内核如何实现?
- 每个进程的
task_struct
结构体里有policy
字段,记录当前调度策略。 - 系统调用
sched_setscheduler
会检查权限(只有 root 可以设置实时策略),然后修改policy
字段,并调整优先级。 - 调度器根据
policy
字段决定该进程用哪种调度算法。
5. 权限限制
- 只有 root 用户才能把进程设置为实时调度(SCHED_FIFO、SCHED_RR、SCHED_DEADLINE),普通用户只能用 SCHED_OTHER、SCHED_BATCH、SCHED_IDLE。
6. 查看进程的调度策略
ps -eo pid,cmd,policy
chrt -p <pid>
7. 总结
进程可以通过系统调用(如 sched_setscheduler)或 chrt 命令选择/更改自己的调度策略。调度策略决定了进程在调度器中的优先级和调度方式。
像在 shell 中运行的进程, 调度策略是怎么被选择的
非常好的问题!
在 shell(比如 bash、zsh)中直接运行的进程,它的调度策略是怎么被选择的?
1. 默认调度策略是什么?
- 在 shell 中直接运行的进程(比如你输入
ls
、vim
、python
等), -
默认使用的是
SCHED_OTHER
(也叫SCHED_NORMAL
,即 CFS 完全公平调度器)。 - 这种策略适用于绝大多数普通用户进程。
2. 为什么是 SCHED_OTHER?
- shell 启动新进程时,调用的是
fork()
+exec()
。 - 新进程会继承父进程(即 shell 本身)的调度策略。
- shell 进程本身也是普通用户进程,默认就是
SCHED_OTHER
。 - 所以,你在 shell 里运行的所有普通命令,默认都是 SCHED_OTHER。
3. 优先级(nice 值)如何确定?
- 默认 nice 值是 0(可以用
nice
命令调整)。 - 你可以用
nice -n 10 command
让进程以较低优先级运行。 - 但这不会改变调度策略,仍然是 SCHED_OTHER,只是优先级(nice)变了。
4. 如何在 shell 里改变调度策略?
- 普通用户不能直接用 shell 改为实时调度策略(SCHED_FIFO、SCHED_RR),需要 root 权限。
- 可以用
chrt
命令(需要 root):
sudo chrt -f 80 ./myprog # 以 SCHED_FIFO 策略、优先级80运行
- 也可以用
nice
调整普通进程的优先级:
nice -n 10 ./myprog # 以较低优先级运行
5. 查看当前进程的调度策略
- 用
ps -eo pid,cmd,policy
或chrt -p <pid>
可以看到进程的调度策略。
6. 总结
在 shell 中直接运行的进程,默认调度策略是 SCHED_OTHER(CFS),优先级由 nice 值决定。只有通过 chrt(需要 root)等方式才能让进程使用实时调度策略。
Linux 调度策略有多个, 那 cpu 轮转的时候具体选择哪个策略呢?
Linux 支持多种调度策略(如 SCHED_OTHER、SCHED_FIFO、SCHED_RR、SCHED_DEADLINE),那 CPU 轮转(调度)时,内核是如何选择用哪个策略的?
1. 调度器的“分层”选择机制
Linux 调度器采用分层优先级的方式来管理不同策略的进程:
A. 实时优先,普通次之
-
实时进程(SCHED_FIFO、SCHED_RR、SCHED_DEADLINE)
- 优先级最高。只要有可运行的实时进程,调度器一定优先调度实时进程。
- 多个实时进程之间,再根据各自的策略和优先级排序。
-
普通进程(SCHED_OTHER、SCHED_BATCH、SCHED_IDLE)
- 只有在没有可运行的实时进程时,调度器才会选择普通进程。
- 普通进程之间再用 CFS(完全公平调度器)等算法排序。
2. 调度器的选择流程(简化版)
每当需要调度(比如时间片用完、进程阻塞/唤醒、系统调用等),调度器会:
-
检查所有可运行的实时进程队列
- 如果有 SCHED_DEADLINE 进程,先选 deadline 最早的。
- 否则,检查 SCHED_FIFO/SCHED_RR 队列,按优先级(1~99)从高到低选择。
- SCHED_FIFO:同优先级下先到先服务,直到主动让出 CPU。
- SCHED_RR:同优先级下轮流分配时间片。
-
如果没有可运行的实时进程
- 选择普通进程队列(CFS),按 vruntime(虚拟运行时间)最小的进程调度。
- SCHED_BATCH、SCHED_IDLE 进程优先级更低,只有系统空闲时才会被调度。
3. 多核系统的情况
- 每个 CPU 都有自己的就绪队列,但调度器的选择逻辑是一样的。
- 进程可以在不同 CPU 之间迁移,调度器会做负载均衡。
4. 源码入口
- 主要在
kernel/sched/core.c
的pick_next_task()
函数。 - 伪代码逻辑如下:
if (有可运行的 SCHED_DEADLINE 进程)
选 deadline 最早的
else if (有可运行的 SCHED_FIFO/SCHED_RR 进程)
选优先级最高的实时进程
else
选 CFS 队列中 vruntime 最小的普通进程
5. 总结
CPU 轮转时,Linux 调度器总是优先选择实时策略(SCHED_DEADLINE > SCHED_FIFO/RR)的进程。如果没有实时进程,才会选择普通策略(SCHED_OTHER/CFS)的进程。每种策略内部再按各自规则排序。