Linux 进程调度全知道

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, &param)
      设置指定进程的调度策略和优先级
    • sched_setparam(pid, &param)
      只设置优先级,不改变策略

示例代码:

#include <sched.h>
struct sched_param param;
param.sched_priority = 80; // 1~99 for real-time
sched_setscheduler(0, SCHED_FIFO, &param); // 把当前进程设置为实时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 中直接运行的进程(比如你输入 lsvimpython 等),
  • 默认使用的是 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,policychrt -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. 实时优先,普通次之

  1. 实时进程(SCHED_FIFO、SCHED_RR、SCHED_DEADLINE)

    • 优先级最高。只要有可运行的实时进程,调度器一定优先调度实时进程
    • 多个实时进程之间,再根据各自的策略和优先级排序。
  2. 普通进程(SCHED_OTHER、SCHED_BATCH、SCHED_IDLE)

    • 只有在没有可运行的实时进程时,调度器才会选择普通进程。
    • 普通进程之间再用 CFS(完全公平调度器)等算法排序。

2. 调度器的选择流程(简化版)

每当需要调度(比如时间片用完、进程阻塞/唤醒、系统调用等),调度器会:

  1. 检查所有可运行的实时进程队列

    • 如果有 SCHED_DEADLINE 进程,先选 deadline 最早的。
    • 否则,检查 SCHED_FIFO/SCHED_RR 队列,按优先级(1~99)从高到低选择。
    • SCHED_FIFO:同优先级下先到先服务,直到主动让出 CPU。
    • SCHED_RR:同优先级下轮流分配时间片。
  2. 如果没有可运行的实时进程

    • 选择普通进程队列(CFS),按 vruntime(虚拟运行时间)最小的进程调度。
    • SCHED_BATCH、SCHED_IDLE 进程优先级更低,只有系统空闲时才会被调度。

3. 多核系统的情况

  • 每个 CPU 都有自己的就绪队列,但调度器的选择逻辑是一样的。
  • 进程可以在不同 CPU 之间迁移,调度器会做负载均衡。

4. 源码入口

  • 主要在 kernel/sched/core.cpick_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)的进程。每种策略内部再按各自规则排序。

©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容

  • 主要参考:Linux manual page - sched 概述 自从linux内核2.6.23以来,默认的进程...
    啊呀哟嘿阅读 791评论 0 0
  • Linux的调度策略区分实时进程和普通进程,实时进程的调度策略是SCHED_FIFO和SCHED_RR,普通的,非...
    x1wan阅读 2,141评论 0 1
  • Linux进程的进程级别分类 普通进程 实时进程 实时进程的优先级都高于普通进程,除此之外,它们的调度策略也有所不...
    码哥说阅读 3,022评论 0 3
  • linux调度类:一共有5个调度类, 每个进程都对应一种调度策略, 每种策略又会对应一种调度类(每个调度类可以对应...
    sk邵楷阅读 695评论 0 1
  • 调度程序负责决定哪个进程投入运行,何时运行以及运行多长时间最大限度提供资源利用率,并且保证公平性 主要内容 多任务...
    leon4ever阅读 656评论 0 1