个人Linux操作系统学习笔记9 - 孤儿进程与进程优先级

📅 2026/7/16 0:17:34 👁️ 阅读次数 📝 编程学习
个人Linux操作系统学习笔记9 - 孤儿进程与进程优先级

目录

  • 孤儿进程
    • 孤儿进程会变成后台进程
  • 进程优先级
    • 什么是优先级?
    • 为什么要有优先级?
    • 进程优先级的变化范围是多少?
    • 为什么只能在这个范围内,不能更改任意数值?
    • 补充概念——竞争、独立、并行、并发
  • 进程切换
    • 进程组织
      • 补充前置知识:

孤儿进程

创建一个孤儿进程:

#include<stdio.h>#include<unistd.h>#include<sys/types.h>intmain(){pid_tid=fork();if(id==0){//childwhile(1){printf("child process, pid: %d, ppid: %d\n",getpid(),getppid());sleep(1);}}else{//parentintcnt=5;while(cnt){cnt--;printf("parent process, pid: %d, ppid: %d, cnt: %d\n",getpid(),getppid(),cnt);sleep(1);}}return0;}

启用“监控”:

while:;dopsajx|head-1&&psajx|grepprocessTest|grep-vgrep;sleep1;echo"=======";done

可以发现,子进程在变成孤儿进程后,ppid会变成1

PPIDPID PGID SID TTY TPGID STATUIDTIME COMMAND1294972949628534pts/228534S10040:00 ./processTest

pid为1的进程一般是操作系统(的一部分),简记为操作系统

为什么孤儿进程要被操作系统领养?

给孤儿进程的退出进行善后,防止一直处于Z状态

被OS领养之后,系统可以进行回收Z状态的孤儿进程


孤儿进程会变成后台进程

当操作系统领养孤儿进程之后,会把孤儿进程变成后台进程,无法使用Ctrl+C杀死该进程

必须使用kill命令

kill-9[pid]

然后它的僵尸会被OS回收


区分前后台进程:

谁能从键盘里获取数据(IO),谁就是前台

键盘只有一个,所以在获取输入的时候,只能有一个进程在获取键盘数据

因此,前台进程在任何时刻只能有一个,后台进程可以有多个


进程优先级

什么是优先级?

权限是“能不能”的问题

优先级是“先后顺序”的问题

优先级:进程在有权限获得某种资源的前提下,得到该资源的先后顺序

为什么要有优先级?

因为资源不足,因此就要分配资源

设置优先级:决定进程获得某种资源的先后顺序


使用ps -la查看更详细的进程信息

$ps-laF SUIDPIDPPIDC PRI NI ADDR SZ WCHAN TTY TIME CMD0S100432355285340800-1054hrtime pts/2 00:00:00 processTest1S100432356323550800-1054hrtime pts/2 00:00:00 processTest0R100432361290130800-38336- pts/3 00:00:00ps

其中UID是进程执行者在操作系统里的身份编号(代表我当前登录的linux账号在系统中的数字编号为1004)

PRI:代表这个进程可被执行的优先级,其值越小越早被执行

NI:代表这个进程的nice值

优先级的本质就是struct task_struct里面的两个整型变量


NI指nice值,是Linux系统特有的,表示:进程可被执行的优先级的修正数值

PRI值越小越快被执行,那么加入nice值之后,将会使得PRI变为:

PRI(new) = PRI(默认值) + nice

因此,当nice值为负值的时候,那么该程序将会优先级值将变小,即其优先级会变高,则其越快被执行

所以,调整进程优先级,在Linux下,就是调整进程nice值
nice其取值范围是-2019,一共40个级别。

nice的默认值为80


有多种方法修改进程优先级:

举最简单的方法为例:

#include<stdio.h>#include<unistd.h>#include<sys/types.h>intmain(){while(1){sleep(1);}return0;}

然后运行该程序

$ps-alF SUIDPIDPPIDC PRI NI ADDR SZ WCHAN TTY TIME CMD0S10041583285340800-1054hrtime pts/2 00:00:00 processTest0R10041619290130800-38336- pts/3 00:00:00ps

然后启动top

$top

在界面中输入r指令,再根据提示输入需要更改的进程的pid,再输入更新后的nice值,即可成功更改

$ps-alF SUIDPIDPPIDC PRI NI ADDR SZ WCHAN TTY TIME CMD0S100415832853409010-1054hrtime pts/2 00:00:00 processTest0R10041844290130800-38336- pts/3 00:00:00ps

如果在完成一次更改之后,又再次尝试更改,会修改失败

因为更改进程优先级不会是一个高频操作,因此频繁修改会被OS阻止

可以使用root账号解除限制


普通用户只能降低进程的优先级(设nice为正数)

root用户才能提高进程优先级(设nice为负数)


进程优先级的变化范围是多少?

PRI范围:6099,因为nice值范围:-2019

相当于有40个梯度

为什么只能在这个范围内,不能更改任意数值?

优先级的变化范围是有限的

主流的操作系统都是分时操作系统——给进程分配时间片,采用特定的调度策略,较为均衡的让不同的进程的能在一段时间内得到CPU资源

如果能够更改为任意数值,可能会出现极大值,导致某个进程的优先级极端高,使得其它进程都无法获得时间片

因此必须使优先级的改变控制在一定范围内!


补充概念——竞争、独立、并行、并发

  • 竞争性: 系统进程数目众多,而CPU资源只有少量,甚至1个,所以进程之间是具有竞争属性的。为了高效完成任务,更合理竞争相关资源,便具有了优先级

  • 独立性: 多进程运行,需要独享各种资源,多进程运行期间互不干扰

  • 并行: 多个进程在多个CPU下分别,同时进行运行,这称之为并行

  • 并发: 多个进程在⼀个CPU下采用进程切换的方式,在⼀段时间之内,让多个进程都得以推进,称之为并发


进程切换

寄存器是共享的,但是寄存器里面的数据,本质是进程私有的,叫做进程上下文

CPU上下文切换:其实际含义是任务切换,或者CPU寄存器切换。当多任务内核决定运行另外的任务时,它保存正在运行任务的当前状态,也就是CPU寄存器中的全部内容。这些内容被保存在任务自己的堆栈中,入栈工作完成后就把下一个将要运行的任务的当前状况从该任务的栈中重新装入CPU寄存器,并开始下一个任务的运行,这一过程就是context switch。


进程组织

Linux内核里面的内核结构:Linux采用链表结构


补充前置知识:

C语言中,任何变量的地址数字,是开辟众多字节中,地址数据最小的那个!

structA{inta;intb;intc;doubled;}

我只知道结构体中C成员的地址,怎么知道所在结构体变量的其它地址呢?

&((structA*)0->c)//是c变量在结构体中的偏移量

c语言提供了宏offsetof获得结构体内变量偏移量

https://legacy.cplusplus.com/reference/cstddef/offsetof/

因此可以使用变量地址 - 偏移量 = 结构体地址获得结构体地址