Linux下进程状态
任何进程在运行时都会有自己的状态
下面的状态在kernel源代码里定义:
/*
* The task state array is a strange "bitmap" of
* reasons to sleep. Thus "running" is zero, and
* you can test for combinations of others with
* simple bit tests.
*/
static const char * const task_state_array[] = {
"R (running)", /* 0 */
"S (sleeping)", /* 1 */
"D (disk sleep)", /* 2 */
"T (stopped)", /* 4 */
"t (tracing stop)", /* 8 */
"X (dead)", /* 16 */
"Z (zombie)", /* 32 */
};
常见的几种状态:
-
R运行状态(running) : 并不意味着进程一定在运行中,它表明进程要么是在运行中要么在运行队列里。
-
S睡眠状态(sleeping): 意味着进程在等待事件完成(这里的睡眠有时候也叫做可中断睡眠(interruptible sleep))。
-
D磁盘休眠状态(Disk sleep)有时候也叫不可中断睡眠(uninterruptible sleep),在这个状态的进程通常会等待IO的结束。
-
T停止状态(stopped): 可以通过发送 SIGSTOP 信号给进程来停止(T)进程。这个被暂停的进程可以通过发送 SIGCONT 信号让进程继续运行。
-
X死亡状态(dead):这个状态只是一个返回状态,你不会在任务列表里看到这个状态。
R、S状态
下来看下面这串代码的运行状态:
#include<stdio.h>
#include<sys/types.h>
#include<unistd.h>
int main()
{
while(1)
{
printf("I am a process,pid:%d\n",getpid());
}
return 0;
}
重复查看代码运行状态:while :; do ps ajx | head -1 && ps ajx | grep testStatus | grep -v grep; sleep 1; done
当程序运行时,显示的是S状态,S状态是休眠状态
将代码中while循环里面打印的内容去掉,再来查看状态:
#include<stdio.h>
#include<sys/types.h>
#include<unistd.h>
int main()
{
while(1)
{
}
return 0;
}
此时代码中只有while死循环,此时是R状态,表示进程正在运行,这个很好理解。
这两个程序刚刚都是运行,为什么第一个代码是S状态(休眠状态)呢?
休眠状态本质上是程序什么都没有做,这叫做休眠状态,但是刚刚一直在打印内容,说是什么都没做,好像有点不对。原因在于:CPU的执行速度很快,比显示器设备显示快的很多,该进程大部分时间都是在显示器的等待队列里等待显示设备就绪,因此最终查看的状态是休眠状态(S状态)。当我们去掉printf
后,进程始终都在运行状态里,所以最终查出来的状态是运行状态(R状态)。
休眠状态本质就是进程在等待“资源”就绪
当程序正在运行时,如果ctrl+c,进程被终止,称为可中断睡眠。
S+:意思是进程在前台运行,S是进程在后台运行
当进程处于后台运行时,无法通过ctrl+c终止程序,需要使用指令:kill -9
T/t状态
T状态和t状态我们可以认为这两个状态是一样的,对于一个进程,可以使用指令kill -19 进程的pid
来让进程处于停止状态
T/t状态:让进程处于暂停状态。
让进程结束暂停状态,继续运行:kill -18 进程pid
当我们使用gdb调试打断点时,遇到断点处就暂停,此时是t状态,这种场景是被追踪暂停。
D状态
D状态:Linux系统比较特有的一种进程状态。在Linux系统层面称作浅度睡眠,S称为深度睡眠。
disk是磁盘的意思,好像是说针对于磁盘的一种状态
有这样一个场景,操作系统中有一个进程,需要将1GB的数据写入磁盘中。首先根据冯诺依曼体系,这个进程要把数据存入磁盘中,实际上是将数据存入外设。进程把数据交给磁盘,磁盘在存储时需要时间,当前进程需要等待,也就是S状态。Linux操作系统负责的是进程管理,文件系统等,整个操作系统管理系统软硬件资源,当系统中整个资源内存不足时,Linux操作系统有权杀掉进程来释放空间。进程在等待磁盘反馈,操作系统忙前忙后,忙的不可开交,看到这个进程:“你干嘛呢?我快忙死了,我快要崩溃了,一旦我崩溃你可知后果??”,操作系统生气了,一气之下把这个进程干掉了,释放了这个进程的内存资源。操作系统继续干自己的事情了,磁盘就说:“不好意思,写入失败,你(进程)跟用户说一下。哎?进程呢?你咋不见了”磁盘在想咋办呢?此时又有新的进程来了,磁盘心想:“不管了,反正之前的进程给的数据写入失败了,先写入新进程的数据吧”。这就造成一批数据丢失问题,如果这个数据很重要,那麻烦大了。用户要对操作系统、磁盘、进程批评审查了。这么一看,操作系统、进程、磁盘好像都没有错,是制度的问题,当进程在向磁盘中写入数据时谁都不能将该进程干掉。于是D状态就诞生了。
当一个进程处于D状态时,它不会响应任何请求,任何人和操作系统都无法干掉这个进程。
结束D状态方式:
- 等待某个条件,比如数据读入完毕
- 直接断电
僵尸进程
- 僵死状态(Zombies)是一个比较特殊的状态。当进程退出并且父进程(使用wait()系统调用,后面讲)没有读取到子进程退出的返回代码时就会产生僵死(尸)进程
- 僵死进程会以终止状态保持在进程表中,并且会一直在等待父进程读取退出状态代码。所以,只要子进程退出,父进程还在运行,但父进程没有读取子进程状态,子进程进入Z状态
代码:
#include<stdio.h>
#include<sys/types.h>
#include<unistd.h>
int main()
{
pid_t id=fork();
if(id==0)
{
int cnt=5;
while(cnt)
{
printf("I am child process,pid:%d,ppid:%d\n",getpid(),getppid());
sleep(1);
cnt--;
}
_exit(0);
}
else
{
while(1)
{
printf("I am father process,pid:%d,ppid:%d\n",getpid(),getppid());
sleep(1);
}
}
return 0;
}
已经运行完毕,但是需要维持自己的退出信息,在自己的进程task_struct
会记录自己的退出信息,未来让父进程来进行读取。如果没有父进程读取,僵尸进程会一直存在。
上述代码中,子进程执行完五次后,就处于Z状态并且后面跟了一个<defunct>
,该单词有不存在的意思,只不过还等待父进程来回收它的资源。处于Z状态的进程的相关资源不能被释放。只有当父进程把子进程的相关资源回收后,子进程才能变成死亡状态(X状态)。一般的,我们讲这种处于Z状态的进程叫做僵尸进程,如果父进程一直不回收,将长时间占用内存资源,造成内存泄漏。
僵尸进程危害:
- 进程的退出状态必须被维持下去,因为他要告诉关心它的进程(父进程),你交给我的任务,我办的怎么样了。可父进程如果一直不读取,那子进程就一直处于Z状态?是的!
- 维护退出状态本身就是要用数据维护,也属于进程基本信息,所以保存在task_struct(PCB)中,换句话说, Z状态一直不退出, PCB一直都要维护?是的!
- 那一个父进程创建了很多子进程,就是不回收,是不是就会造成内存资源的浪费?是的!因为数据结构对象本身就要占用内存,想想C中定义一个结构体变量(对象),是要在内存的某个位置进行开辟空间!
- 内存泄漏?是的!
孤儿进程
僵尸进程代码中是子进程先退出,父进程一直运行
在孤儿进程中,让父进程先退出,子进程一直运行
代码:
#include<stdio.h>
#include<sys/types.h>
#include<unistd.h>
int main()
{
pid_t id=fork();
if(id==0)
{
int cnt=500;
while(cnt)
{
printf("I am child process,pid:%d,ppid:%d\n",getpid(),getppid());
sleep(1);
cnt--;
}
_exit(0);
}
else
{
int cnt=5;
while(cnt--)
{
printf("I am father process,pid:%d,ppid:%d\n",getpid(),getppid());
sleep(1);
}
}
return 0;
}
父进程结束后,只剩下子进程,为什么父进程不会处于僵尸进程?父进程也是bash的子进程,父进程结束后,它的父进程bash会将它回收掉,并且过程很快,所以父进程不会处于僵尸状态。
当父进程结束后,它的子进程的父进程变成1号进程,即操作系统
将父进程是1号进程的进程叫做孤儿进程。 孤儿进程被1号i进程领养,当然要有进程回收喽。文章来源:https://www.toymoban.com/news/detail-853964.html
文章来源地址https://www.toymoban.com/news/detail-853964.html
到了这里,关于探索Linux下进程状态 | 僵尸进程 | 孤儿进程的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!