Linux中进程的六种状态

Linux中进程的六种状态

目录

  • R运行状态(running)
  • S睡眠状态(sleeping)
  • D磁盘休眠状态(Disk sleep)
  • T停止状态(stopped)
  • Z僵尸状态(Zombies)
    • 僵尸进程是什么
    • 为什么要有僵尸进程
    • 僵尸进程的危害
  • X死亡状态(dead)
  • 孤儿进程

为了弄明白正在运行的进程是什么意思,我们需要知道进程的不同状态。一个进程可以有几个状态(在Linux内核里,进程有时候也叫做任务)。

Linux中进程的六种状态_第1张图片

Linux中进程的六种状态_第2张图片

R运行状态(running)

并不意味着进程一定在运行中,它表明进程要么是在运行中要么在运行队列

问题:如果只有一个CPU,可不可以存在多个R状态的进程。
现场试一下:用fork创建子进程,试一下
在这里插入图片描述
Linux中进程的六种状态_第3张图片

Linux中进程的六种状态_第4张图片
可以看到,是可以存在多个运行状态的。
进程是R状态,不代表正在运行,代表可被调度。换句话说,进程只有是R状态才可被调度,其他状态要先转为R状态,才能被OS调度。
Linux中进程的六种状态_第5张图片

S睡眠状态(sleeping)

意味着进程在等待事件完成(这里的睡眠有时候也叫做可中断睡眠(interruptible sleep))。
代码实现一下:
Linux中进程的六种状态_第6张图片

在这里插入图片描述
休眠状态是在等待某种条件就绪,在休眠状态,可被操作系统杀死,也叫浅度睡眠。

处于这个状态的进程因为等待某某事件的发生(比如等待socket连接、等待信号量),而被挂起。这些进程的task_struct结构被放入对应事件的等待队列中。当这些事件发生时(由外部中断触发、或由其他进程触发),对应的等待队列中的一个或多个进程将被唤醒。

Linux中进程的六种状态_第7张图片
由上图看到,一般情况下,进程列表中的绝大多数进程都处于S状态(除非机器的负载很高)。毕竟CPU就这么一两个,进程动辄几十上百个,如果不是绝大多数进程都在睡眠,CPU又怎么响应得过来。

D磁盘休眠状态(Disk sleep)

有时候也叫不可中断睡眠状态(uninterruptible sleep),在这个状态的进程通常会等待IO的结束。

可是为什么有了S状态,又来一个D状态呢?有什么作用呢?
举例说明:
Linux中进程的六种状态_第8张图片

T停止状态(stopped)

可以通过发送 SIGSTOP 信号给进程来停止(T)进程。这个被暂停的进程可以通过发送 SIGCONT 信号让进程继续运行。

Z僵尸状态(Zombies)

代码实现一下僵尸状态:
子进程5秒结束,父进程死循环,不读取子进程结束信息。

Linux中进程的六种状态_第9张图片
Linux中进程的六种状态_第10张图片
Linux中进程的六种状态_第11张图片
5秒之后,子进程变为僵尸状态。

僵尸进程是什么

是一个比较特殊的状态。当子进程退出并且父进程没有读取到子进程退出的返回代码时,就会产生僵死(尸)进程,
僵死进程会以终止状态保持在进程表中,并且会一直在等待父进程读取退出状态代码。所以,只要子进程退出,父进程还在运行,但父进程没有读取子进程状态,子进程进入Z状态。

为什么要有僵尸进程

因为我们必须得保证一个进程跑完,启动这个进程的父进程或是操作系统必须得知道这个进程退出时,把我们交代得任务完成得怎么样了,成功还是失败了。必须要知道子进程得运行结果。当子进程退出的时候,它的信息不会立即释放,会存在PCB中,没有人读取,这个状态不会被释放掉,这个状态就是僵尸状态。

僵尸进程的危害

进程的退出状态必须被维持下去,因为他要告诉关心它的进程(父进程),你交给我的任务,我办的怎样了。可父进程如果一直不读取,那子进程就一直处于Z状态?是的!

维护退出状态本身就是要用数据维护,也属于进程基本信息,所以保存在task_struct(PCB)中,换句话说,Z状态一直不退出,PCB一直都要维护?是的!

那一个父进程创建了很多子进程,就是不回收,是不是就会造成内存资源的浪费?是的!

因为数据结构对象本身就要占用内存,想想C中定义一个结构体变量(对象),是要在内存的某个位置进行开辟空
间!内存泄漏?是的!

X死亡状态(dead)

这个状态只是一个返回状态,你不会在任务列表里看到这个状态。当父进程读取子进程的返回结果时,子进程立刻释放资源。死亡状态是非常短暂的,几乎不可能通过ps命令捕捉到。

孤儿进程

所谓孤儿进程,故名思义,和现实生活中的孤儿有点类似,当一个进程的父进程结束时,但是它自己还没有结束,那么这个进程将会成为孤儿进程。

孤儿进程会被init进程(1号进程)的进程收养,当然在子进程结束时也会由init进程完成对它的状态收集工作,因此一般来说,孤儿进程并不会有什么危害.
代码实现一下:

#include 
#include 
#include 
int main()
{
pid_t id = fork();
if(id < 0){
perror("fork");
return 1;
}
else if(id == 0){//child
printf("I am child, pid : %d\n", getpid());
sleep(10);
}else{//parent
printf("I am parent, pid: %d\n", getpid());
sleep(3);
exit(0);
}
return 0;
}

Linux中进程的六种状态_第12张图片
由图可以看出,当父进程结束时,父进程由4416变为1号进程,子进程4417被1号进程领养。

你可能感兴趣的:(C语言,linux,windows,c++,c语言)