16 | 调度(中):主动调度是如何发生的?
刘超
该思维导图由 AI 生成,仅供参考
上一节,我们为调度准备了这么多的数据结构,这一节我们来看调度是如何发生的。
所谓进程调度,其实就是一个人在做 A 项目,在某个时刻,换成做 B 项目去了。发生这种情况,主要有两种方式。
方式一:A 项目做着做着,发现里面有一条指令 sleep,也就是要休息一下,或者在等待某个 I/O 事件。那没办法了,就要主动让出 CPU,然后可以开始做 B 项目。
方式二:A 项目做着做着,旷日持久,实在受不了了。项目经理介入了,说这个项目 A 先停停,B 项目也要做一下,要不然 B 项目该投诉了。
主动调度
我们这一节先来看方式一,主动调度。
这个片段可以看作写入块设备的一个典型场景。写入需要一段时间,这段时间用不上 CPU,还不如主动让给其他进程。
另外一个例子是,从 Tap 网络设备等待一个读取。Tap 网络设备是虚拟机使用的网络设备。当没有数据到来的时候,它也需要等待,所以也会选择把 CPU 让给其他进程。
你应该知道,计算机主要处理计算、网络、存储三个方面。计算主要是 CPU 和内存的合作;网络和存储则多是和外部设备的合作;在操作外部设备的时候,往往需要让出 CPU,就像上面两段代码一样,选择调用 schedule() 函数。
公开
同步至部落
取消
完成
0/2000
荧光笔
直线
曲线
笔记
复制
AI
- 深入了解
- 翻译
- 解释
- 总结
本文深入介绍了进程调度的发生方式,主要分为主动调度和被动调度。主动调度发生在进程自身需要让出CPU的情况下,通过调用schedule()函数来主动让出CPU,让其他进程执行。文章通过代码片段展示了两种主动调度的情况,分别是Btrfs文件系统等待写入和Tap网络设备等待读取。接着详细解释了schedule()函数的调用过程,包括获取下一个任务、上下文切换等步骤。文章通过代码解析展示了调度类的调用过程,以及CFS调度类的pick_next_task_fair函数的实现。此外,文章还介绍了进程上下文切换的实现细节,包括内存空间的切换、寄存器和栈的切换,以及Per CPU的结构体tss的作用。通过深入的代码分析,生动地展现了主动调度的发生过程,对于理解进程调度机制有很好的帮助。
仅可试看部分内容,如需阅读全部内容,请付费购买文章所属专栏
《趣谈 Linux 操作系统》,新⼈⾸单¥68
《趣谈 Linux 操作系统》,新⼈⾸单¥68
立即购买
© 版权归极客邦科技所有,未经许可不得传播售卖。 页面已增加防盗追踪,如有侵权极客邦将依法追究其法律责任。
登录 后留言
全部留言(54)
- 最新
- 精选
- 憨人进程切换需要搞明白:我从哪里来,我要到哪里去
作者回复: 这句话赞
2019-05-1727 - 安排proc文件系统里面可以看运行时间和切换次数,还可以看自愿切换和非自愿切换次数。 老师请教一个问题,A切到B, B切到C,C切到A,当最后切换回A的时候,A要知道自己是从C切换过来的,也就是last,这样做的目的是什么呢?A要对C做什么善后操作吗?
作者回复: 是的 finish_task_switch完成清理工作
2019-05-0327 - 刘強看了三遍,因为有一些基础,大概明白了。我觉得有个地方很巧妙。当函数返回的时候,由于切换了上下文,包括栈指针,所以一个进程函数执行return返回到了另一个进程,也就是完成了进程的切换。由此也可以看出,cpu也是比较"笨的",它只提供了基本的机制,至于如何利用这种机制,玩出花样,那就是各个操作系统自由发挥了。
作者回复: 是的,这一点比较绕
2019-05-05416 - 尚墨刘老师,每个用户的进程都会被分配一个内核栈吗?
作者回复: 是的
2019-05-0829 - kdb_reboot补充一下,看了最后的那张图,感觉切换,就是切内核态的 stack/rsp/pc, 这样下一个任务就能找到在哪执行了,以及继续怎么执行, 而内核态共享一片内存空间,所以不需要mm_switch,切换完了,返回用户态,用户态的stack/rsp/pc都被切换了, 而用户态的内存空间需要单独切换 老师,我理解的对吧?
作者回复: 是的
2019-07-278 - 蹦哒“cpu_init会给每一个 CPU 关联一个 TSS,然后将 TR 指向这个 TSS,然后在操作系统的运行过程中,TR 就不切换了,永远指向这个 TSS” 看到这里,想到了一个设计模式:享元模式(Flyweight Design Pattern)
作者回复: 牛,这是从设计模式专栏过来的吧
2020-06-147 - kdb_reboot看起来ps 里面的TIME就是进程的 cpu runtime吧; 查看上下文切换,可以用cat /proc/x/status
作者回复: 赞
2019-07-276 - kdb_reboot关于指令指针的讲解,厉害了... 专栏有时候可以反者看, 先看最后总结,然后往上顺藤模块看你的分析 同时在读的书:lkd/ulk, 推荐给大家
作者回复: 先看总结也挺好的
2019-07-273 - garlic通过ps -o etime= -p "$$" 可以 查看,进程的运行时间, 通过/proc/{pid}/status 中的 voluntary_ctxt_switches: nonvoluntary_ctxt_switches: 可以看到主动调度和抢占调度的次数, 也可以单独安装sysstat 使用pidstat -w 查看相关进程的调度信息 https://garlicspace.com/2019/07/20/查看进程运行时间及上下文切换次数/
作者回复: 赞
2019-07-202 - 栋能我有两个问题,希望老师解解惑: 1.文中说进程切换会从红黑树中找到最左结点,如果不等于当前进程,则切换。但如果更新vruntime之后,树结构还是没变呢,即最左还是等于当前进程,那我当前进程切换不是又没效果了吗?(这点有疑问,是我理解vruntime是公平的,但主动调度一定存在某种情况,如vruntime变化不大,树结构不变的?) 2.在指令指针的恢复与保存这部分内容中,你说A调用__schedule进行切换,在运行到finish_task_switch时进程已经是B了。你觉得这里没有问题,是因为A、B进程都是调用过__schedule方法进行进程切换,最后都执行finish_task_switch就是圆满了。可是进程切换除了主动调用之外,还有时间片用完,如B进程可能并没有调用过__schedule,那如果A进程切换,导致B进程执行finish_task_switch方法,那这是不是个问题呢?本来进程B并不需要执行它的。
作者回复: 1.如果最左面的节点还是自己,并且自己还能运行,也即还是running状态,那就接着运行,说明时间片用完了,但是没有更加高级的需要运行,如果是等待IO,那就不是running状态,则不在树中。 2.调度第一定律,B如果当年被调度走,哪怕是时间片到,也是调用了schedule的
2019-07-1652
收起评论