Linux核心概念详解
  • 0. Linux核心概念详解
  • 1. 调试环境
  • 2. Linux 调度器
    • 2.1 任务
    • 2.2 核心概念
      • 2.2.1 核心概念 - 调度实体
      • 2.2.2 核心概念 - 调度类
      • 2.2.3 核心概念 - 调度策略
      • 2.2.4 核心概念 - 运行队列
      • 2.2.5 核心概念 - 优先级
    • 2.3 演进历史
      • 2.3.1 O(n)调度器 - 调度逻辑
      • 2.3.2 O(n)调度器 - 时间分配
      • 2.3.3 O(n)调度器 - 调度时机
      • 2.3.4 O(1)调度器 - 简介
      • 2.3.5 O(1)调度器 - 调度逻辑
      • 2.3.6 O(1)调度器 - 时间分配
      • 2.3.7 RSDL
      • 2.3.8 CFS
    • 2.4 DL调度器
      • 2.4.1 DL调度器 - 调度算法
      • 2.4.2 DL调度器 -核心代码
    • 2.5 RT调度器
    • 2.6 CFS
      • 2.6.1 公平性
      • 2.6.2 调度逻辑
      • 2.6.2.1 调度逻辑 - 数据结构
      • 2.6.2.2 调度逻辑 - vruntime
      • 2.6.2.3 调度逻辑 - 调度周期
      • 2.6.2.4 调度逻辑 - 调度节拍
      • 2.6.2.5 调度逻辑 - 任务抢占
      • 2.6.2.6 调度逻辑 - 调度时机
      • 2.6.3 组调度
      • 2.6.3.1 组调度 - 数据结构
      • 2.6.3.2 组调度 - 调度逻辑
      • 2.6.3.3 组调度 - 时间分配
      • 2.6.3.4 组调度 - 任务组权重
      • 2.6.4 带宽控制
      • 2.6.4.1 带宽控制 - 数据结构
      • 2.6.4.2 带宽控制 - 带宽时间
      • 2.6.4.3 带宽控制 - 挂起与解挂
      • 2.6.4.3 带宽控制 - 定时器
    • 2.7 负载追踪
      • 2.7.1 负载追踪 - 简介
      • 2.7.2 负载追踪 - 数据结构
      • 2.7.3 负载追踪 - 计算负载
      • 2.7.4 负载追踪 - 更新负载
    • 2.8 负载均衡
      • 2.8.1 简介
      • 2.8.2 CPU的拓扑结构
      • 2.8.3 数据结构
      • 2.8.4 算法思路
      • 2.8.5 触发时机
      • 2.8.6 总结
  • 3. LINUX 内存管理
    • 3.1 寻址模式
      • 3.1.1 地址
      • 3.1.2 地址转换
      • 3.1.3 Linux的地址空间
    • 3.2 物理内存
      • 3.2.1 数据结构
      • 3.2.2 初始化
      • 3.2.3 物理内存模型
      • 3.2.4 Buddy System(伙伴系统)
      • 3.2.5 SLAB/SLUB/SLOB
Powered by GitBook
On this page

Was this helpful?

  1. 2. Linux 调度器

2.1 任务

Previous1. 调试环境Next2.2 核心概念

Last updated 3 years ago

Was this helpful?

进程是现代操作系统中最重要的概念之一,一个进程表示程序的一个执行实例。进程本身也是一个动态的概念,代表着程序一次从头到尾的执行过程,因此进程有自己的生命周期,可能处于不同的状态,这方面的资料已经非常丰富,就不在这里赘述了,感兴趣的同学就可以了。

然而在Linux中,进程并不是最小的执行单元,系统中最小的执行单元是线程(Thread)。但在内核层面并没有对进程与线程做显示的区分,二者统一都叫着任务(Task),区别体现在对资源的共享程度上:进程本质上是对资源的一种抽象与隔离,包括内存地址空间、文件、信号量等,Linux在通过系统调用 clone 创建一个新的 task 时,如果所有的资源都不共享,那么对用户而言就是创建了一个新的进程,如果除了函数调用栈(Stack)不共享、其他所有资源都共享,则创建的便是一个线程。

Linux 使用 task_struct 来表示一个任务,其定义如下:

/* file: include/linux/sched.h */
struct task_struct {
    /* 与优先级相关的字段 */
    int prio;
    int static_prio;
    int normal_prio;

    unsigned int rt_priority;

    /* 调度策略 */
    const struct sched_class *sched_class;
    /* 调度实体,调度器的调度对象,该字段用于 CFS */
    struct sched_entity se;
    /* 该字段用于 RT 调度器 */
    struct sched_rt_entity rt;
#ifdef CONFIG_CGROUP_SCHED
    struct task_group *sched_task_group;
#endif
    /* 该字段用于 DL 调度器 */
    struct sched_dl_entity dl;
}

task_struct 是一个非常大的结构体,包含了进程运行时的所有信息,这里我们只罗列出了几个与调度逻辑相关的字段,这些字段的作用在本章的后续章节中会做进一步分析。

从调度的角度来看,不同类型进程的调度需求是不一样的:

  • 交互式进程(Interactive Process) 进程运行过程中需要不断通过 I/O 与用户交互,由于用户行为的速度与CPU的执行的速度有巨大落差,所以在 OS 看来这类进程大多数时间都在等待I/O事件。

    为了提升用户体验,该类进程最好能够有较好的响应时间,即一旦用户完成了操作,我们希望进程能够以最快地速度完成响应。所以对于调度器而言,如果这类进程是就绪的,那么最好立刻执行他们。也就是说,这类进程应该具备较高的优先级。

  • 批处理进程(Batch Process) 这类进程几乎没有交互需求,只要他们在后台默默运行就好。用户对他们的期望是有足够大的吞吐量,因此每次被调度到时,最好都能稳稳当当运行一段时间,以便能够更好的利用CPU缓存以提升效率。

  • 实时进程(Real-time Process) 这类进程对响应时间要求极高,因此一旦进程处于就绪状态,就需要立刻扔到 CPU 上执行。

在接下来的章节中,我们将详细探讨Linux对进程的调度原理,弄清楚内核如何区分不同类型的进程,并着重分析CFS调度期的实现细节。

上网搜