[Linux]初识进程
进程
什么是进程
一个运行起来的程序就是进程。程序的本质是一个文件,它存储在磁盘中,而进程是已经被加载到了内存的程序。
进程 = 内核数据结构 + 进程对应的代码。
如何管理进程
当有多个程序被加载到内存,被CPU
执行的时候。操作系统为了管理(管理的本质逻辑逻辑都是:先描述,再组织。描述:是指将某些东西的共同属性拿出来形成一个结构体或和类,组织:将对象通过某种数据结构联系起来)这些进程,要为每一个进程创建对应的pcb
(是一个struct task_struct{};
结构体,包含了该进程的所有属性和对应代码的地址),描述完成之后,再把所有创建完的结构体对象组织起来。所以对进程的管理就变成了对数据结构的增删查改。
查看进程的方式
-
ps ajx | head -1 && ps ajx | grep mytest
-
ls /proc/
常见的进程调用
-
getpid()
:查看进程的pid
。 -
getppid()
:查看进程的ppid
,也就是该进程父进程的pid
。每一次重新运行程序的时候,它的
pid
都会改变,而ppid
却一直不变。这是因为命令行上启动的进程,一般它的父进程没有特殊情况的话都是bash
,而bash
是我们登录时系统就为我们分配,直到我们退出之前都不会改变。 -
fork()
:创建子进程程序执行在
fork()
函数之前只有一个执行流,在fork()
函数之后会产生两个执行流,所以它才会有两个返回值,将子进程的pid
返回给父进程,将0
返回给子进程。
进程状态
在一个进程的生命周期中,并不是一直处于运行的状态,它受到多种因素的影响体现出不同的状态。
操作系统层面
- 运行态:当一个进程正在CPU上运行或者在CPU的运行队列中。
- 阻塞态:进程在执行过程中,由于等待某一事件(如 I/O 操作完成、等待某个信号量、等待另一个进程的消息等)的发生而暂时无法继续执行的状态。在这个状态下,进程会让出 CPU,暂停自身的执行,直到等待的事件满足后才有可能被重新调度执行。操作系统会为每个处于阻塞态的进程维护一个等待队列,将阻塞进程加入到对应设备的阻塞队列中。
- 挂起态:由于内存空间不够,操作系统会将某些进程的代码和数据暂时保存到磁盘上,以节省内存空间。
Linux层面
-
R 运行状态(running):进程正在使用CPU执行指令。但也有可能处在运行队列里等待被调度运行,这种也属于运行态。
-
S 睡眠状态(sleeping):也称为可中断睡眠,意味着进程等待事件完成。
#include <stdio.h> int main() { int flag = 0; int a = 0; while(1) { a = 1 + 1; printf("a的值是:%d,flag:%d\n", a, flag); flag++; } return 0; }
从上述代码的执行结果可以发现,为什么程序任然在执行,但却显示的是睡眠状态?
那是因为当程序进行
printf
操作的时候,由于printf
会访问显示器,而显示器又属于外设,进程访问外设的时间相对于CPU来说是很慢的,因此当查看进程状态的时候,进程几乎都会处于睡眠状态。 -
T 停止状态(stopped):可以发送SIGSTOP来使进程暂停运行,发送SIGCONT信号可以使进程重新恢复运行。
停止:
继续运行:
-
D 磁盘休眠状态(Disk sleep):又称为不可中断睡眠。在该状态的进程,无法被操作系统杀掉,只能通过断电或者进程自己醒来来解决。
-
X 死亡状态(dead):在进程列表中通常不可见。进程已经完全结束,资源已经完全释放,仅仅作为一个概念存在。
-
t 跟踪状态(Trace):当进程正在被跟踪(例如程序在调试时)所处的状态。
-
Z 僵尸状态(Zombie):进程退出的时候不能立即释放所拥有的资源,而是要保存一段时间,让父进程或操作系统来读取。若父进程或操作系统没有回收子进程的资源,此时子进程就会变为僵尸状态。由于僵尸状态的进程还会保留一定的资源,因此若有过多的僵尸进程存在则可能会导致资源耗尽等问题。
-
以下是一个僵尸进程的例子:
#include <stdio.h> #include <unistd.h> #include <stdlib.h> int main() { pid_t id = fork(); if (id == 0) { printf("子进程pid:%d, ppid:%d\n", getpid(), getppid()); sleep(5); exit(1); } else { printf("父进程pid:%d, ppid:%d\n", getpid(), getppid()); sleep(60); } return 0; }
运行截图
进程状态后面的”+“表示这个进程是否是前台进程。带加号的是前台进程,此时输入的命令不会被立即执行。并且ctrl + c
可以终止它。而不带加号的是后台进程,可以正常的输入命令来进行交互。但是无法通过ctrl + c
来终止它。
孤儿进程
孤儿进程是指它的父进程已经结束运行,而自己仍然在运行的进程。
当父进程结束运行时,它的所有子进程会被操作系统的init
进程接管,init
进程的进程id通常为1,它会负责完成这些孤儿进程的后续资源回收等清理工作。而且一般孤儿进程都是后台进程,需要kill
指令结束进程。
进程优先级
由于系统中的资源是有限的,因此有了进程优先级这个概念。进程优先级是决定一个进程获得某种资源的先后顺序。

- PRI:是priority的缩写,一个进程的PRI值代表了它可被执行的优先级程度。数值越小,优先级越高。(默认值是80)
- NI:是nice的缩写,NI的范围是[-20,19]。一个进程的最终优先级的计算方式为:PRI = PRI(默认) + NI。
通过TOP命令可以改变NI的值,进而影响最终PRI。TOP命令使用方法是:top -> 输入r -> 输入进程pid -> 输入NI值
进程切换
由于CPU资源有限,一个进程在CPU上运行的时候并不是一直占有直到进程结束,而是在不断的进行进程的切换,从而实现多任务处理。
当一个进程执行完一个时间片之后,就会进行进程的切换,如此循环往复,就形成了进程间的轮转调度。
那么当一个进程的时间片执行完成之后,当它下次又要被执行的时候,CPU是如何知道从什么地方开始执行呢?
那是因为在CPU的内部有一套寄存器,这套寄存器被所有进程共享,这些寄存器保存了当前进程执行的一些数据,当进程被切换的时候,这些数据会被保存到进程的内核栈中,然后再将另一个进程内核栈中对应的寄存器数据恢复到CPU上,这样就可以让CPU继续从上次被切换的位置继续向下执行。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南