目录
前言
这篇文章我们来认识一下孤儿进程与进程优先级切换调度,接下来来跟随小编的视角来学习一下吧
let's go!!!!!!!!
Part1. 孤儿进程
父进程先于子进程死亡,子进程就变成孤儿进程。
1. 孤儿进程会被pid=1的init/systemd进程领养,成为init的子进程。
2. 为什么需要领养?
如果不领养,当子进程退出之后,没有父进程回收,孤儿进程就会变成僵尸进程,持续占用PCB资源。3. 领养之后,init进程作为父进程,会自动回收孤儿进程退出后的资源。
4. 孤儿进程会自动变为后台进程:ctrl + c无法杀死,只能使用kill -9 pid杀掉。
Part2. 进程优先级
Part2.1. 概念
进程优先级决定进程获取CPU资源的先后顺序。
CPU资源是有限的,优先级高的进程,优先拿到CPU时间片。
Linux中优先级由两个数值表示:
• PRI:进程真实优先级,默认80,数值越小,优先级越高。
• NI(nice值):优先级修正数据。
真实优先级公式:PRI = 80 + nice
nice取值范围:‑20 ~ 19
对应真实PRI优先级范围:60 ~ 99
注意:nice值越小,代表修正越高,最终PRI越小,进程优先级越高。
Part2.2. 修改进程优先级
方式1:top命令
1. 输入top进入工具
2. 按下r
3. 输入目标进程pid
4. 输入要设置的nice值
方式2:命令行 nice / renice
# 启动进程时直接设置nice,x为nice值,y为程序名
nice -n x y# 修改已经运行进程的nice,x为nice值,y为pid
renice x -P y
Part2.3. 系统API修改优先级
// 获取优先级 int getpriority(int which, id_t who); /* which: PRIO_PROCESS:按进程pid; PRIO_PGRP:按进程组; PRIO_USER:按用户uid; who:对应id,填0代表当前自身 */ // 设置优先级,prio就是nice值 int setpriority(int which, int who, int prio);普通用户只能降低优先级(nice变大);root用户可以随意修改到‑20最高优先级。
p.s. 优先级不能差距拉得太大,操作系统兼顾公平性,高优先级只是获取更多时间片,不会完全霸占CPU。
Part2.4. UID
操作系统看用户,依靠UID(ls -ln可以查看)。
子进程继承父进程的UID;UID代表进程属于哪个用户。
Linux内核依靠UID做权限校验,控制进程访问资源。
Part3. 时间片、进程切换
Part3.1. 并行与并发
• 并发:多个进程快速切换,单个CPU,交替执行多个进程。每个进程拿到一小段CPU时间片。
• 并行:多个CPU核心,多个进程同时真正运行。
p.s. 多核CPU才存在并行;单核CPU只有并发。
Part3.2. 进程切换机制
CPU不会把一个进程执行完毕才切换。操作系统分配时间片,给每一个进程一小段CPU执行时间。
时间片耗尽,触发时钟中断,保存当前进程上下文,切换到另外一个进程。
Part3.3. 进程上下文
CPU内部寄存器集合,保存当前进程运行现场:程序计数器、通用寄存器等。
进程被切出去的时候,把寄存器现场保存到TSS任务状态段;当进程再次被调度回来,把现场恢复到寄存器,从上一次中断位置继续运行。
上下文就是进程运行的全部硬件现场,没有上下文,进程就无法继续执行。
Part4. Linux O(1)调度器原理
Linux经典O(1)调度器,每一个优先级对应一条调度队列。
Part4.1. 调度队列结构
1. 一共140个优先级,0~139,对应queue[140]数组。数组每一个元素,是一条双向链表,存放对应优先级的进程(task_struct)。
2. 维护两个位图bitmap[140/8],一共140bit。每一个bit代表对应优先级链表是否存在就绪进程。bit置1代表该优先级队列里面有就绪进程。
3. 两套调度结构体:active(活跃队列,还没消耗完时间片)、expired(过期队列,时间片耗尽)。
◦ active:存放还拥有剩余时间片,可以继续调度运行的进程。
◦ expired:进程时间片用完,放入expired队列,等待所有active进程全部调度完毕,再交换两个队列。
4. nr_active:记录active队列里面总就绪进程数量。
Part4.2. O(1)找到最高优先级进程
1. 读取bitmap位图,找最低的置1的bit位,这个bit下标就是当前最高就绪优先级。
2. 通过下标,直接访问queue[优先级]链表,取出链表头部进程,送入CPU运行。
p.s. 找最高优先级只需要一次位运算,时间复杂度O(1),所以叫O(1)调度器。
Part4.3. 调度流程
1. 通过bitmap找到最高优先级;
2. 将该优先级链表头部进程摘出来,交给CPU执行;
3. 进程时间片耗尽,把进程放入expired过期队列;
4. 不断重复调度,直到nr_active == 0,active队列全部进程时间片耗尽;
5. 交换active与expired结构体指针,expired直接变成新的active队列,继续调度。
why: 为什么修改nice值,不去直接修改PRI
运行中的进程,修改NI(nice),不修改当前正在使用的PRI。不会立刻把进程挪动队列。
等到该进程时间片耗尽,进入expired队列的时候,再重新计算新PRI,放入对应优先级链表。避免调度过程中打乱队列。
p.s. 补充负载均衡
多CPU环境,每个CPU都拥有自己一套独立的active/expired调度结构体。
调度器会统计各个CPU的负载load,在多个CPU之间迁移进程,平衡各个CPU的任务数量。
Part5. 结语
这篇文章我们认识并知道了孤儿进程与进程优先级切换调度,接下来,小编还会带来更多Linux相关的知识,敬请期待~
最后,祝大家可以:春风得意马蹄疾,一日看尽长安花!
最后的最后,要是觉得本文还可以的话,可以点点赞,关注小编一波,谢谢大家!~
转载自 CSDN-专业IT技术社区
原文链接:https://blog.csdn.net/2501_93971468/article/details/164187820





