【liunx】进程的状态

1.进程的状态

我们或多或少了解到进程的状态分为:
运行,新建,就绪,挂起,阻塞,等待,停止,挂机,死亡…

首先解释一点,进程这么多状态,本质上都是用来满足不同运行场景的。

接下来我们从两个方面来理解进程的状态

1.普遍的操作系统层面理解进程的概念

在这里插入图片描述

总结:
1.一个cpu一个运行队列
2.让进程进队列,本质上是将进程的task_struct结构体对象放在运行队列中
3.进程pcb在运行队列,就是R,不是这个进程正在运行,才是运行状态

状态其实是进程内部的属性,放在task_struct,本质是就是int类型的数字来表示不同的状态(假如1:run 2:stop …)。

我们知道磁盘速度都是很慢的,进程或多或少会访问磁盘,但是磁盘也只有一个,那该怎么办呢?
只能是等待

4.不要只以为,你的进程只会等待(占用)cpu资源,你的进程也可能随时随地要外设资源。

扫描二维码关注公众号,回复: 17276939 查看本文章

在这里插入图片描述

当cpu发现某个进程需要访问磁盘,就会把该进程从运行队列中剥离,如果这个磁盘现在正由其他进程使用,操作系统就会把该进程放在磁盘的等待队列里(将task_struct对象放在不同队列中),该进程会由运行状态变成阻塞状态。,当磁盘处理完进程,但是等待队列中的进程还是阻塞状态,操作系统会把该进程拿到系统中,把状态改成R(运行状态)再给cpu的运行队列中。

5.所谓的进程不同的状态,本质是进程在不同的队列中,等待某种资源。

进程处于阻塞状态,可能不会被立即调度,万一阻塞的进程有很多,内存空间不够了怎么办?
在这里插入图片描述

操作系统会把该进程对应的代码和数据暂时保存到磁盘上,pcb还在内存。这样就节省了一部分空间,然后把这一部分空间给别人使用。
在这里插入图片描述
此时的进程就处于挂起状态

将进程的代码和数据,加载或者保存到磁盘叫做内存数据的唤入换出

阻塞并不一定挂起,挂起一定阻塞。

进程的状态我们这里就说这么多,主要要知道,1.什么叫做运行;2.什么叫做阻塞;3.什么叫做挂起。

接下来我们从另一方面来了解进程

2.Linux是怎么做的(具体的linux操作系统的状态)

STAT 状态

#include<stdio.h>
   
   int main()
   {
    
    
   
       while(1)
       {
    
    }
                                                                                                                                                                    
      return 0;
  }

在这里插入图片描述

R+ 运行

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

int main()
{
    
                                                                                                                                                                       
	int a=0;
	while(1)
	{
    
    
		printf("%d\n",a++);
		sleep(1);
	}
  
	return 0;
}

在这里插入图片描述

S+ 休眠

printf会把内容打印到显示器上去,显示器是一个外设,外设特点就是慢,等待显示器就绪,cpu需要花较长的时间。99%都是在等IO就绪,1%再执行打印代码。

所有进程访问外设行为基本都是S(阻塞状态的一种)

kill -l  //查看kill命令

在这里插入图片描述

kill -19 编号  //暂停进程

在这里插入图片描述

T 暂停(阻塞的一种)

kill -18 编号 //继续进程

在这里插入图片描述
这里注意一点,在睡眠的状态是S+,当我暂停进程,又继续进程之后。这个进程状态就变成S了;

状态后面带+,属于前台进程,在xshell输入任何指令没用,除了用ctrl+c,结束进程。
状态后面不带+,属于后台进程,在xshell输入指令都有效,使用ctrl+c不能结束进程,只能使用kill -9 杀死进程。

在这里插入图片描述
ctrl+c不能杀死后台程序

在这里插入图片描述
输入指令还有效

在这里插入图片描述
对于后台程序只能通过kill -9 杀死进程。

D 深度睡眠

讲个小故事帮助我们理解D状态。

今天我想让进程帮我向磁盘写个超大份的数据,磁盘答应给我写,那么磁盘就开始写了。写了一会操作系统发现我们电脑变得很卡,操作系统是很聪明的,它去查看,发现这个进程导致电脑变卡,如果不删去这个进程而去删别的进程就会导致其他进程有意见,所以操作系统决定给它删了,过了一会磁盘写数据遇见错误,呼叫进程,但是进程被删了,所以最终导致写入数据失败。当我发现写入数据失败,我问它们三个到底是谁的责任?

请问是操作系统的责任吗?请问是进程的责任吗?请问是磁盘的责任吗?

操作系统回答说,不是我的责任,这是我们赋予它的权力,为了保证系统正常运行。
进程回答说,不是我的责任,我是被操作系统给删掉了。
磁盘回答说,也不是我的责任,我只负责任写。

那么为了想把数据写到磁盘里,我只能给这个进程发一个免死金牌,让操作系统不能删掉它。

像在高级IO的情况,该进程就处于D(深度睡眠),在该状态的进程,无法被操作系统杀掉!只能通过断电,或者进程自己醒来才能解决

S+ 休眠,属于浅度睡眠可以被终止

t 也是暂停状态,表示该进程正在被追踪,等待指令,当调试的时候。出现该状态

在这里插入图片描述

在这里插入图片描述

X(dead)死亡状态

Z(zombie)僵尸状态

2.僵尸进程

为什么会有僵尸状态?(感性的认识)
进程被创建出来,是为了完成任务。
1.要知道它完成的如何。2.不关系结果。

Linux是一个你可以不要,但我要给。
所以进程退出的时候,不能立即释放该进程对应的资源(代码和数据释放掉,PCB保留),保存一段时间,让父进程或者操作系统来进行读取,因什么原因而退出。这段时间内进程处于僵尸状态。

所谓僵尸状态就是:当进程退出的时候,如果没有对该进程回收,此时进程处于僵尸。

我们在linux下见见僵尸状态
具体做法,子进程退出,但是父进程和操作系统没有对其回收------> 创建一个子进程,让父进程不要退出,而且什么都不做,让子进程正常退出即可。

#include<stdio.h>
#include<unistd.h>
#include<stdlib.h>
int main()
{
    
    
    pid_t id=fork();
    if(id == 0)
    {
    
    
         //子进程
         int cnt=10;
         while(cnt--)
         {
    
    
             printf("子进程, pid : %d , ppid : %d  ,ret : %d ,cnt=%d\n",getpid(),getppid(),id,cnt);
             sleep(1);
         }                                                                                                                                                        
         exit(-1);
     }
     else if(id > 0)
     {
    
    
 
        //父进程
        while(1)
        {
    
    
             printf("父进程, pid : %d , ppid : %d  ,ret : %d\n",getpid(),getppid(),id);
             sleep(3);
        }
     }
     return 0;
 }

在这里插入图片描述
在这里插入图片描述

3.孤儿进程

所谓孤儿进程就是,当父进程先退出,这个子进程会被操作系统(1号进程)领养,这个子进程叫做孤儿进程。

这里要说明的是:
1.父进程先退出这种情况一定是存在的。
2.子进程会被操作系统(1号进程)领养。
3.那为什么要领养呢?
如果不领养,那么子进程退出的时候,对应的僵尸便没有人能回收了。造成了资源浪费。
4.被领养的进程----孤儿进程
5.如果是前台进程创建的子进程,变成了孤儿,会自动变成后台程序,只能被杀死。

int main()
{
    
    
    pid_t id=fork();
    if(id > 0)
    {
    
    
         //父进程
         int cnt=10;
         while(cnt--)
         {
    
    
             printf("父进程, pid : %d , ppid : %d  ,ret : %d ,cnt=%d\n",getpid(),getppid(),id,cnt);
             sleep(1);
         }                                                                                                                                                        
         exit(-1);
     }
     else if(id > 0)
     {
    
    
 
        //子进程
        while(1)
        {
    
    
             printf("子进程, pid : %d , ppid : %d  ,ret : %d\n",getpid(),getppid(),id);
             sleep(3);
        }
     }
     return 0;
 }

在这里插入图片描述
在这里插入图片描述
发现当父进程退出,子进程会被操作系统(1号进程领养)。并且子进程由前台程序变成了后台程序,只能被杀死。

在这里插入图片描述

关于进程的状态我们就说这么多,喜欢的点赞,评论,收藏+关注。下篇继续了解更多关于进程的知识。

猜你喜欢

转载自blog.csdn.net/fight_p/article/details/132739280