[Linux]进程
Linux进程
- 进程概念
- task_struct内容分类
- 标识符
- 状态
- 优先级
- 程序计数器PC/EIP
- 其他
- 进程
- 查看进程
- 通过系统调用创建进程
- Linux进程状态
- R状态
- S状态
- D状态
- T状态
- Z状态
- X状态
- 孤儿进程
- 进程优先级
- 查看系统进程
- top命令更改已存在进程的nice值
- 环境变量
- 环境变量基本概念
- 常见的环境变量PATH : 指定命令的搜索路径
- 常见的环境变量HOME : 指定用户的主工作目录
- 常见的环境变量SHELL : 值通常是/bin/bash
- 其他概念
进程概念
课本概念:程序的一个执行实例,正在执行的程序等
内核观点:担当分配系统资源(CPU时间,内存)的实体
系统中可以同时存在大量的程序
Windows下的进程:
Linux下的进程:
操作系统如何管理进程?——先描述(需要有PCB——描述进程的结构体),在组织
操作系统如何通过 PCB 管理进程?
若有 100 个进程,则有 100 个 PCB(一个PCB对应一个进程),操作系统通过以下方式组织和管理这些 PCB:
1、链表或表结构:
PCB 通常以 链表 或 表(如进程表) 形式组织,便于快速遍历和查找。
例如:就绪队列、阻塞队列分别链接对应状态的进程 PCB。
2、进程生命周期管理:
创建进程:分配 PCB,初始化字段(如 PID、状态、资源)。
销毁进程:回收 PCB,释放内存和资源。
3、上下文切换:
当进程切换时,操作系统通过 PCB 保存当前进程的寄存器、程序计数器等状态,并加载下一个进程的状态。
4、资源分配与权限控制:
通过 PCB 中的资源列表和权限信息,操作系统确保进程只能访问合法资源(如防止越权访问文件)。
1、进程 > 可执行程序 :因为进程 = 可执行程序 + 内核数据结构
2、为什么会存在PCB?——操作系统需要软硬件管理,所以需要有PCB
所为的创建/删除进程就是对应的添加节点或是删除节点,即对进程的管理就是对链表的增删查改
Linux描述进程是用struct task_struct{}
包含:
1、pid、ppid
2、优先级
3、能够找到对应的代码与数据
4、时间片
5、上下文信息
6、连接信息(PCB与PCB之间的联系)
7、…
task_struct内容分类
标识符
来查询看看进程情况:
myproc就是一个正在运行的进程
ps aux查找所有的进程
杀掉进程:
之后运行程序:
可以发现pid会一直变化,但是ppid(父进程id)是没有任何变化的
干掉该进程后,会直接掉线
登录成功的时候,就会自动创建一个bash
状态
S:休眠状态 -> 这里是显示的一瞬间状态
依然是sleep——printf是往外设打印,外设很慢,os调用的时候,大部分时间都在休眠
这次取消外设printf试验:
此时就变成了R状态
R与R+表示这里程序是在前台跑还是后台跑
如何删后台进程——kill命令
优先级
什么是优先级?——获得资源的优先级
vs权限 : 权限——能或不能 优先级——能的前提下谁先谁后
为什么要有优先级?——资源有限
CPU资源是有限的,但是进程是可以有多个的,因此进程需要优先级设置
进程排队——PCB结构体进行排队
程序计数器PC/EIP
程序中即将被执行的下一条指令的地址,进程在切换的时候,需要保护数据之后恢复
在 Linux 系统中,PCB的具体实现就是 task_struct 结构体。它是操作系统内核中用于描述和管理进程的核心数据结构,每个进程(或线程)在内核中都有一个对应的 task_struct,记录了进程的所有运行时信息。
用户双击 app.exe:
操作系统从硬盘加载app.exe到内存,创建task_struct,初始化进程。进程加入就绪队列:
调度器选择该进程,分配CPU时间片。CPU 执行指令:
取指令 → 解码 → 执行,PC逐步更新。进程结束:
执行exit()系统调用,操作系统回收内存和PCB。
其他
内存指针: 包括程序代码和进程相关数据的指针,还有和其他进程共享的内存块的指针
上下文数据: 进程执行时处理器的寄存器中的数据。
在操作系统中,上下文数据是指进程执行时处理器的寄存器中保存的当前运行状态信息。这些数据是进程在CPU上运行时的实时快照,用于在进程切换时保存和恢复进程的执行环境。
上下文被保存至进程控制块里面(task_struct)
I/O状态信息: 包括显示的I/O请求,分配给进程的I/O设备和被进程使用的文件列表。
记账信息: 可能包括处理器时间总和,使用的时钟数总和,时间限制记账号等。
进程
查看进程
在根目录下有proc 这里也可以查进程
ls /proc/PID
打开当前进程信息
cwd:
通过系统调用创建进程
fork()创建子进程
其中的22883(fork的父是bash)
以 .bash 开头的文件是 Bash Shell 的配置文件,位于用户的主目录(~)下,用于自定义 Shell 环境和行为。
fork创建子进程,fork之前的代码被父进程执行,fork之后的代码,默认情况被父子都可以执行
原程序进程的父进程:
当用户在终端中运行 ./myproc 时,启动该程序的父进程是 Shell(如 bash 或 zsh)。此时原程序的 PPID(父进程 ID)是 Shell 的 PID。
子进程的父进程:
通过 fork() 创建的子进程,其父进程是 原程序进程(即调用 fork() 的进程)。子进程的 PPID 是原程序进程的 PID,而非 Shell 的 PID。
假设原程序进程的 PID 是 1000,Shell 的 PID 是 500,则输出为:
hello
I am a process->pid: 1000, ppid: 500 ← 父进程(原程序)
I am a process->pid: 1001, ppid: 1000 ← 子进程
fork创建的子进程,与父进程链接起来(双链表)-> 此时系统内多了一个进程
子进程执行的代码和数据来源于父进程
fork() 前的代码:
仅由父进程执行一次,子进程不会重复执行,例如 printf(“hello \n”) 只输出一次。
fork() 后的代码:
父子进程各自独立执行,互不干扰。
例如 while(1) 循环会在两个进程中持续运行。
父子进程关系:
父进程(原程序)的父进程是 Shell(如 bash)。
子进程的父进程是原程序进程,而非 Shell。
fork之后,父子进程代码共享
fork之后,就有了2个进程,这两个进程调度先后是不确定的,取决于调度算法
fork函数会有2次返回值(为什么?——后续提及),给父进程返回pid,给子进程返回0
可以使用fork进行分流:
Linux进程状态
R状态
R运行状态(running): 并不意味着进程一定在运行中,它表明进程要么是在运行中要么在运行队列(所有R状态全在一个队列上)里。
进程是R状态 -> 不代表正在运行,而是代表可以被调度
因此 一个CPU可以同时存在多个R状态的进程
S状态
S睡眠状态(sleeping): 意味着进程在等待事件完成(这里的睡眠有时候也叫做可中断睡眠(interruptible sleep))。 S 在Linux是浅度睡眠->通常是进程等待某一个事件发生
D状态
D磁盘休眠状态(Disk sleep)有时候也叫不可中断睡眠状态(uninterruptible sleep),在这个状态的进程通常会等待IO的结束。 在Linux中D是深度睡眠
D状态:表示该进程不会被杀掉,即便你是操作系统;除非是自己主动醒来,才可以恢复
T状态
T停止状态(stopped): 可以通过发送 SIGSTOP 信号给进程来停止(T)进程。这个被暂停的进程可以通过发送 SIGCONT 信号让进程继续运行。
列出信号:执行 kill -l 会显示当前系统支持的信号列表。这些信号用于进程间通信,例如终止进程、重新加载配置等。
杀死后会变成T状态:暂停,暂时不跑,让其先暂停
让其继续运行:SIGCONT
Z状态
Z(zombie)-僵尸进程
僵死状态(Zombies)是一个比较特殊的状态。当进程退出并且父进程(使用wait()系统调用,后面讲)没有读取到子进程退出的返回代码时就会产生僵死(尸)进程僵死进程会以终止状态保持在进程表中,并且会一直在等待父进程读取退出状态代码。所以,只要子进程退出,父进程还在运行,但父进程没有读取子进程状态,子进程进入Z状态
通俗来说,进程退出的时候,在系统层面,曾经申请的资源并不是被立即释放的,而是要暂存一段时间,供OS(父进程)进行读取 -> 僵尸状态
进程被创建的目的是为了完成某种工作、任务;在任务完成的时候,调用方也应该需要知道任务完成情况(除非不关心完成情况)
echo $? 是最近一次进程退出时候的退出码 return
为什么需要僵尸进程?——需要知道一个任务的完成情况,进程退出的信息(退出码)是会被暂时保存起来(task_struct)而非立即释放,如果没有人读取,此时task_struct相关数据是不应该被释放 此时这种状态就是僵尸。
以上代码结果是:子进程提前结束,但是父进程一直执行,子进程没有被访问,一直保持僵尸状态
创建僵尸进程的例子:
监视脚本
while :; do ps aux | head -1 && ps aux | grep myproc | grep -v grep; echo"##################"; sleep 1; done
此时可以看到僵尸进程
X状态
X死亡状态(dead):这个状态只是一个返回状态,你不会在任务列表里看到这个状态。
在 Linux 进程管理中,X(死亡状态,Dead) 是进程生命周期中的一个最终状态,表示进程已完全终止且其资源(如内存、文件句柄等)已被系统回收。
总结:
僵死状态(Zombies)是一个比较特殊的状态。当进程退出并且父进程(使用wait()系统调用,后面讲),没有读取到子进程退出的返回代码时就会产生僵死(尸)进程
僵死进程会以终止状态保持在进程表中,并且会一直在等待父进程读取退出状态代码。
所以,只要子进程退出,父进程还在运行,但父进程没有读取子进程状态,子进程进入Z状态
孤儿进程
在Linux中,进程关系主要就是父子关系;父进程退出了,子进程还在运行,形成为孤儿进程。子进程也退出的时候,形成了僵尸,谁来回收?——若未回收会导致内存泄漏,因此子进程退出后会立即被系统领养变成1号进程
进程优先级
cpu资源分配的先后顺序,就是指进程的优先权(priority)。
优先权高的进程有优先执行权利。配置进程优先权对多任务环境的linux很有用,可以改善系统性能。
还可以把进程运行到指定的CPU上,这样一来,把不重要的进程安排到某个CPU,可以大大改善系统整体性能
查看系统进程
对比:
ps -l:当前用户的进程详情(长格式)。ps -la:所有用户的进程(长格式,但过滤系统进程)。
在linux或者unix系统中,用ps –l命令则会类似输出以下几个内容:
1、PRI也还是比较好理解的,即进程的优先级,或者通俗点说就是程序被CPU执行的先后顺序,此值越小,进程的优先级别越高
2、那NI呢?就是我们所要说的nice值,表示进程可被执行的优先级的修正数值,PRI值越小越快被执行,那么加入nice值后,将会使得PRI变为:PRI(new)=PRI(old)+nice,这样,当nice值为负值的时候,那么该程序将会优先级值将变小,即其优先级会变高,则其越快被执行,所以,调整进程优先级,在Linux下,就是调整进程nice值,nice其取值范围是-20(若修改为-100 超过范围默认还是-20)至19,一共40个级别。 其中每一次修改优先级的时候PRI(old)都是从80调整
3、需要强调一点的是,进程的nice值不是进程的优先级,他们不是一个概念,但是进程nice值会影响到进程的优先级变化。
4、可以理解nice值是进程优先级的修正修正数据
UID : 代表执行者的身份
PID : 代表这个进程的代号
PPID :代表这个进程是由哪个进程发展衍生而来的,亦即父进程的代号
PRI :代表这个进程可被执行的优先级,其值越小越早被执行
NI :代表这个进程的nice值
top命令更改已存在进程的nice值
top
进入top后按“r”–>输入进程PID–>输入nice值
输入top: 类似于Windows下的任务管理器
找到进程对应的PID
修改nice值为10
此时PRI也变成了90
环境变量
环境变量基本概念
环境变量(environment variables)一般是指在操作系统中用来指定操作系统运行环境的一些参数,环境变量实际上就是一个变量。
如:我们在编写C/C++代码的时候,在链接的时候,从来不知道我们的所链接的动态静态库在哪里,但是照样可以链接成功,生成可执行程序,原因就是有相关环境变量帮助编译器进行查找。
环境变量通常具有某些特殊用途,还有在系统当中通常具有全局特性。
通俗来说:环境变量就像操作系统中的「隐形小助手」,它们是一组动态的值,用来告诉系统和应用程序如何运行、去哪里找资源、如何配置自己。你可以把它们想象成贴在系统各个角落的「便利贴」,程序运行时随时会查看这些便利贴来获取关键信息。
查看环境变量的方法:
echo $NAME //NAME:你的环境变量名称
常见的环境变量PATH : 指定命令的搜索路径
那么为什么我们使用ls不需要./ls 而使用自己make后的则需要./myproc才能执行呢?两者都是可执行的变量
查看系统环境变量:
echo $PATH
每个冒号之间的内容就是路径,执行ls命令的时候,默认从左到右依次在路径中查找ls
操作系统在环境变量中能够找到ls命令,因此ls可以不带路径直接执行
如果我想直接执行myproc 而非是输入./myproc怎么做?
sudo cp -f myproc /usr/bin 此方法不推荐
此时就可以直接执行了
sudo rm /usr/bin/myproc 删除掉
export PATH=$PATH:/home/zmm/os/3_9
建议的方法:将当前路径加入至环境变量中
PATH:系统用于查找可执行文件的路径列表。
$PATH:表示当前 PATH 的值。
$PATH:/home/zmm/os/3_9:在原有路径末尾追加新目录,用冒号 : 分隔。
效果:
用户可以在任何目录下直接运行 /home/zmm/os/3_9 中的可执行文件,无需输入完整路径。
将目录 /home/zmm/os/3_9 添加到环境变量 PATH 中。
执行以下命令的时候,大部分指令都会失效
此时说明PATH就是一个变量
常见的环境变量HOME : 指定用户的主工作目录
HOME:即用户登陆到Linux系统中时,默认的目录
此时可以得知不同用户HOME不一样
常见的环境变量SHELL : 值通常是/bin/bash
定义用户默认 Shell:
SHELL 环境变量存储了当前用户登录时默认使用的 Shell 程序的绝对路径。例如:
/bin/bash(Bash Shell)
/bin/zsh(Zsh Shell)
/bin/sh(POSIX Shell)
系统行为依赖:
某些程序或脚本会根据 SHELL 的值决定如何执行命令或配置环境。
env显示当前环境变量的信息
给其他用户发送命令
who可以查看有多少用户
echo "xxx信息" > /dev/pts/1
其他概念
竞争性: 系统进程数目众多,而CPU资源只有少量,甚至1个,所以进程之间是具有竞争属性的。为了高效完成任务,更合理竞争相关资源,便具有了优先级
独立性: 多进程运行,需要独享各种资源,多进程运行期间互不干扰
并行: 多个进程在多个CPU下分别,同时进行运行,这称之为并行
并发: 多个进程在一个CPU下采用进程切换的方式,在一段时间之内,让多个进程都得以推进,称之为并发
4核处理器"并不意味着有4个独立的物理CPU,而是指单个物理CPU芯片内部集成了4个独立的核心。