进程的7种状态,僵尸进程与孤儿进程

时间:2024-03-07 08:26:51

一.进程的七种状态
1.七种状态如下:
①R(运行状态)(这个状态并不是说明当前进程在CPU里运行,而是说当前进程处理运行队列里)
②S(浅度睡眠状态)
③D(深度睡眠状态)(不能被终止)
④T(停止状态)
⑤t  (追踪状态)
⑥X(死亡状态)
⑦Z(僵尸状态)
注意:状态后面带+表示前台进程,不带+表示后台进程(前台进程:当前只能有一个进程做事;后台进程:当前可以有很多进程做事)
2.如何修改进程的状态?

①首先创建一个进程,并让其变成一个后台进程(后面加上一个&)。
②我们可以看到test进程的pid为1785,状态为R(下面还有一个进程是执行查询进程信息时创建的进程grep)。
③将test进程的状态由R变为T(停止)状态。
首先通过kill -l查询这些信号处理列表。

可以发现19号信号(SIGSTOP)是停止进程的信号。
执行19号信号:(kill -19 1785)注意必须在19前面加上-(也可以将19换为信号名,如可以写kill -SIGSTOP 1785)
④如果想让刚刚停止的进程继续执行,则可以用kill -18 1785
二.僵尸进程
1.什么叫僵尸进程?
当一个子进程退出后,其父进程还在继续执行,子进程的退出信息并没有被父进程接收到,但是一个进程的退出信息必须被父进程或一些有联系的进程接收到,所以当前进程会一直处于僵死状态。
2.为什么子进程的退出信息要被接收到呢?
因为一个进程的退出方式有三种(程序执行完结果正确即正常退出,程序执行完结果不正确,程序还没有执行完),父进程必须要知道子进程到底是以何种状态退出的,如果子进程不是正常退出,则父进程还要创建子进程执行这件事。
3.处于僵尸状态的进程会一直等待其父进程读取其退出信息。
4.所以,只要子进程退出,而父进程还在执行,但父进程没有读取子进程的状态信息,则子进程会变成一个僵尸进程。
5.创建一个僵尸进程(只要让子进程先退出,父进程一直执行) 
例如可以编写一个程序,前5秒该程序会让父子进程同时运行,5秒之后只有父进程在一直运行,所以我们可以知道5秒后子进程的状态会变为Z状态。

#include<stdio.h>
#include<unistd.h>
#include<stdlib.h>

int main()
{
//先创建一个子进程
pid_t pid = fork();
if (pid == 0)
{
//child
//让子进程先退出,父进程一直执行

printf("child pid=%d ppid=%d\n", getpid(), getppid());
sleep(5);
exit(1); //让子进程睡5秒后推出
}
else if (pid > 0)
{
//parent
//让父进程一直执行
while (1)
{
printf("parent pid=%d ppid=%d\n", getpid(), getppid());
sleep(2); //让父进程每隔两秒打印这个
}
}
}

 

6.在另一个终端下启动监控,查看进程的状态:
启动监控的命令如下:while :;do ps aux | grep \'jiangshi\' | grep -v grep;sleep 1;echo "#####################################";done
则命令执行后的结果如下:(可以发现5秒后子进程由S状态变为Z状态)
三.因为僵尸进程的是由于父进程没有接收到子进程的返回信息,那么僵尸进程肯定是有危害的,那么僵尸进程有什么危害呢?
1.一个进程当他处于僵尸状态时,它这个状态会一直维持下去,因为它必须要告诉父进程它的返回信息。
2.又由于操作系统必须要用数据来维持一个进程的状态,所以僵尸状态也是进程的基本信息,也需要PCB来维护,所以一个处于僵尸状态的进程一直需要维护。维护就会有空间的消耗,这些消耗的空间又没有被释放,所以就会导致内存资源的浪费,就会导致内存泄露的问题。
(补充一点,不只是C语言或C++里指针没有释放会导致内存泄露,这里的僵尸状态没有被处理也会导致内存泄露)。
注意:当一个进程变为僵尸进程后,无法用kill -9来杀死这个进程。

四.如何避免僵尸进程?
1.僵尸进程是由于子进程退出但是父进程没有接收其退出信息而导致了。
2.只要让子进程退出后,父进程接收子进程的退出信息就可以避免僵尸进程。
3.所以父进程通过进程等待的方式,回收子进程的资源,获取子进程的信息。

五.孤儿进程
1.什么是孤儿进程?
当一个子进程还在执行时,它的父进程已经退出了,那么这个子进程的退出信息也没有被父进程接收到,如果子进程的退出信息没有被别的进程接收到,那么这个子进程就会变成一个僵尸进程,所以孤儿进程可能会引发僵尸进程。所以这个子进程必须被其他进程所领养,领养它的进程为1号进程,则它的退出信息会被1号进程所接收。
2.如果父进程退出,父进程会变成僵尸进程吗?
不会,因为父进程的父进程为bash,父进程的退出信息会由bash接收到,这些我们看不到。
3.创建一个孤儿进程(只需要让父进程先退出,子进程继续执行)

#include<stdio.h> 
#include<unistd.h>
#include<stdlib.h>

int main()
{
//孤儿进程:父进程先退出,子进程继续执行
pid_t pid = fork();
if (pid == 0)
{
//子进程
while (1)
{
printf("child pid=%d ppid=%d\n", getpid(), getppid());
sleep(3);
}
}
else if (pid > 0)
{
//parent
printf("parent pid=%d ppid=%d\n", getpid(), getppid());
sleep(5);
exit(1);
}
else
{
perror("fork()");
}
return 0;
}

 

4.打开一个监控,由于这里还需要看到父进程的id,所以这里的启动监控的命令改为while :;do ps axj | grep \'guer\' | grep -v grep;sleep 1;echo "###################################################################";done

执行结果:(我们可以发现5秒之后子进程的父进程变为1号进程,说明当5秒之后父进程退出后,子进程被1号进程领养)