大家好,我是苏貝,本篇博客带大家了解Linux进程(1),如果你觉得我写的还不错的话,可以给我一个赞👍吗,感谢❤️
目录
- (A)R/S/D/T/t状态
- 1. R:程序运行的状态
- 2. S:休眠状态
- 3. T/t:暂停进程
- 4. D(disk sleep):不可被kill杀,深度睡眠,不可中断睡眠
- (B)僵尸进程(Z)
- (C)孤儿进程
其实进程状态只是PCB的一个属性,即是Linux下task_struct结构体的一个属性
所以如果进程状态被修改了,即task_struct结构体里的status属性被修改了
下图是进程的7种状态
(A)R/S/D/T/t状态
进程一共有7种状态,下面我们来一一介绍
1. R:程序运行的状态
先来写makefile文件,将上面的makefile文件复制过来,内容如下:
这时我决定将新的.c文件命名为testStatus.c,可执行文件命名为testStatus,为了方便,我们可以在尾行模式下执行下面代码,一键将myprocess替换成testStatus
不过这只对单纯的myprocess替换,若后面带了.c或其它后缀,可能不能替换
写出下面代码
编译.c文件,运行进程,通过每秒显示的进程信息中我们发现,进程处于S+状态,而非R状态(运行状态),这是为什么?
将.c文件修改一下,去掉打印
再来看看进程的状态,发现这时又是R状态,这又是什么原因呢?
第一种情况:
需要打印,所以要与外设显示器打交道。CPU将处理的结果传到内存中,再从内存传到显示器文件里。在此期间,CPU处理得到1个结果可能只需要几纳秒,而显示器打印可能需要几毫秒,所以在第二次得到CPU处理的结果时,进程要等待显示器响应。在我们循环打印时,进程在绝大多数情况下都要等待显示器响应,所以进程显示S状态。
第二种情况:
不需要打印,所以不需要和外设打交道,因此进程不需要等待响应,所以进程处于R状态
2. S:休眠状态
处于S状态有两种可能:
一是进程在等待资源就绪(上面的第一种情况),二是可中断睡眠
可中断睡眠:处于睡眠状态,但是随时可以被外部因素(如CTRL+C)打断
展示一下:修改.c文件
运行进程2秒后CTRL+C可以结束进程
我们发现,S状态后面还跟着一个+,这是什么意思?
S+:表示进程在前台运行
S:表示进程在后台运行
用下面命令就能用代码让进程在后台运行
后台运行的进程不能被CTRL+C结束,需要用kill -9 pid结束
3. T/t:暂停进程
暂停的进程会等待被唤醒。如何暂停进程呢?也要用kill命令
先来查看所有的kill信号
我们上面的kill -9 pid就是使用了9号信号:SIGKILL,作用是杀掉进程。现在来学习19号和18号信号:SIGSTOP和SIGCONT,作用分别是暂停进程和唤醒进程
先修改.c文件
用了kill -19 pid后,进程状态确实变成了T(暂停状态)
我们继续让暂停的进程被唤醒,用kill -18 pid
注意:一个进程在被暂停和被唤醒后,会自动变成后台运行(状态后面没有+)
其实我们在学习进程状态之前就有用过暂停进程,比如:调试
调试时,遇到断点就会暂停进程
在调试前,注意要在gcc后面加-g,这样形成的才是可被调试的debug模式,否则默认是不可被调试的release模式
进入调试,在第10行打断点,运行进程。到断点位置,进程暂停,T状态。gdb里执行c(continue)继续进程,S状态。再到断点位置,进程暂停,T状态
4. D(disk sleep):不可被kill杀,深度睡眠,不可中断睡眠
D状态是Linux系统比较特有的一种状态,不可被kill杀,只能等待进程自己醒来。如果想杀掉进程,只能重启,甚至于断电
(B)僵尸进程(Z)
在Linux中,进程=内核数据结构task_struct+进程的代码和数据。一个已经运行完毕的进程,代码和数据都不再使用,所以它们的空间会被释放。但进程要维持自己的退出信息,退出信息位于内核数据结构task_struct中,未来让父进程进行读取。如果没有父进程读取,该进程虽然已经运行完毕但task_struct会一直存在,即僵尸进程,task_struct占的空间非常大,这就导致内存泄漏。
先修改.c文件
上面代码是说,子进程循环3次就结束进程,父进程一直存在但不会读取子进程的退出信息
我们可以看到,在子进程结束后,并没有退出,而是以僵尸进程的形式存在。
我们同样发现,处于Z状态时进程名会发生改变,且后面带有,这也是在告诉我们该进程是僵尸进程
在后面我们还会学习让父进程读取子进程的退出信息的函数waitpid(),读取的瞬间子进程变成X状态,再由操作系统释放
我们以前启动的所有的进程,为什么没有关心过僵尸进程呢?也就是为什么我们没有关心内存泄漏问题?因为直接在命令行中启动的进程,它的父进程是bash,bash会自动读取新进程的退出信息,然后由操作系统释放
(C)孤儿进程
父进程如果先退出,子进程就会变成孤儿进程。为了保证子进程被正常回收,孤儿进程一般都会被1号进程(可以理解为操作系统)领养。
修改.c文件
父进程退出后,子进程(pid=7966)就变成孤儿进程,此时的父进程为1号进程
好了,那么本篇博客就到此结束了,如果你觉得本篇博客对你有些帮助,可以给个大大的赞👍吗,感谢看到这里,我们下篇博客见❤️