Linux基础4-进程2(Linux中的进程状态,R,S,D,T,t,Z,X,僵尸进程,孤儿进程)

上篇文章:Linux基础4-进程1(操作系统,进程介绍,Linux进程相关命令,getpid,fork)-CSDN博客

本章重点:

进程状态相关知识

目录

[1. 进程常见的状态](#1. 进程常见的状态)

2.普遍的操作系统理解进程状态

[3. Linux操作系统是如何区分这些状态的](#3. Linux操作系统是如何区分这些状态的)

3.Linux中查看进程状态

[3.1 R(运行状态)与 S(睡眠状态)](#3.1 R(运行状态)与 S(睡眠状态))

[3.2 T(停止状态)状态, t(短暂暂停)状态,D(深度睡眠)状态](#3.2 T(停止状态)状态, t(短暂暂停)状态,D(深度睡眠)状态)

[3.2.1 前后台进程](#3.2.1 前后台进程)

[3.2.2 t状态](#3.2.2 t状态)

[3.2.3 D状态](#3.2.3 D状态)

[4. Z状态与僵尸进程](#4. Z状态与僵尸进程)

[5. 孤儿进程](#5. 孤儿进程)

[6. 下章重点](#6. 下章重点)

[6.1 进程优先级](#6.1 进程优先级)

[6.2 进程的竞争性,独立性,并发,并行](#6.2 进程的竞争性,独立性,并发,并行)


1. 进程常见的状态

运行,新建,就绪,挂起,阻塞,等待,停止,挂机,死亡等

2.普遍的操作系统理解进程状态

在os中,os会管理一个运行队列

1 一个cpu会拥有一个运行队列

2 让进程进入运行状态的本质,将进程对象的task_struct(进程控制块PCB)放入运行队列

3 进程对象的PCB在进程队列中,该进程的状态才是运行状态,并不是进程在运行就是运行状态

4 进程会等待占用CPU资源,进程也会去占用外设的资源

5 操作系统通过将进程对象的PCB放到不同的执行队列来改变其状态

6 所谓的进程不同的状态,本质是在不同的执行队列中,等待某种资源

关于阻塞和挂起:

阻塞状态是当进程需要资源而处于等待时的状态。

阻塞状态的进程可能不会立即被调度,它会占用内存来等待资源。

但是,被阻塞的进程状态过多,内存资源会不够,这个时候操作系统就会把这些进程的数据和代码保存在磁盘上。

这样就能够节省一定的内存资源,将进程的这种状态称为挂起状态。

当被挂起的状态等待的资源到达时,操作系统再将磁盘的数据和代码加载到内存中继续运行。

两种状态之间的转化如下:

3. Linux操作系统是如何区分这些状态的

上图是Linux 代码中对进程状态的描述

有R(运行状态) S(睡眠状态) D(深度睡眠) T(停止状态) t(短暂停止) Z(僵尸状态) X(死亡状态) 七种状态

3.Linux中查看进程状态

3.1 R(运行状态)与 S(睡眠状态)

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

int main()
{
  while(1)
  {
    int a = 1;
    a+=1;
  }
  return 0;
}

该代码是一个死循环,方便我们观察状态

适当修改代码,死循环的同时打印a值

cpp 复制代码
#include<stdio.h>
#include<unistd.h>
#include<stdlib.h>

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

这个由R状态变为S状态的原因:

printf输出到外设(显示器),进程需要等待显示器就绪,需要等待较长的时间(相对于cpu)

所以:99%显示的是S状态,1%显示的是R状态

3.2 T(停止状态)状态, t(短暂暂停)状态,D(深度睡眠)状态

cpp 复制代码
kill -19 进程pid    //可以停止这个进程
kill -18 进程pid    //可以重启暂停的进程

暂停状态是阻塞状态还是挂起状态?

对于用户来说:暂停状态就是阻塞了,是否挂起我们不知道

对于OS来说:是否要挂起阻塞状态由OS自行决定(用户不需要知道阻塞状态是否需要被挂起)

继续运行暂停的进程

使用 kill -18 之后,被暂停的process重新变成了S状态。

但是却不是变回S+,这是为什么??

我们使用 ctrl c 都无法强制退出process,这是因为process变为了后台进程

3.2.1 前后台进程

状态前面带+号的是前台进程,不带+号的是后台进程

后台进程无法使用ctrl c 终止,只能使用 kill 杀死

当一个前台进程被kill -19 暂停后,使用 kill -18恢复运行就会由前台进程变为后台进程

3.2.2 t状态

t状态是暂短暂停状态,如使用gdb调试一个进程的时候,该进程会处于t

3.2.3 D状态

在D状态下的进程无法被杀死,只有通过断电,或者进程自己醒来,自己解决

4. Z状态与僵尸进程

处于Z状态的进程称为僵尸进程。

当子进程退出之后,父进程没有读取到子进程的返回状态,子进程就会变为僵尸进程。且僵尸进程会一直等待父进程读取退出状态

子进程被创建出来 --> 为了完成任务 --> 父进程需要知道子进程完成的怎么样(通过子进程的退出信息)

当子进程退出了,父亲却没有回收子进程,这是一个问题!

只要我们创建一个父子进程,让父进程不退出,也不回收子进程。再让子进程退出,就能观察到处于僵尸状态的子进程

下面代码父亲处于死循环且不会回收子进程,子进程5秒后退出。

子进程退出之后就会变为僵尸进程

cpp 复制代码
#include<stdio.h>
#include<unistd.h>
#include<stdlib.h>
int main()
{
  pid_t id=fork();
  if(id==0)//正常为子进程
  {
    //childi
    printf("我是子进程,我的pid为%d,我的ppid为%d\n",getpid(),getppid());
     sleep(5);
     exit(1);
   }
   else 
   {
     //parent
     while(1)
     {
       printf("我是父进程,我的pid为%d,我的ppid为%d\n",getpid(),getppid());
       sleep(1);
     }
   }
   return 0;
 }

僵尸进程会占用内存,又不会被回收,这样会导致内存泄漏

5. 孤儿进程

如果子进程退出,父进程不回收子进程退出信息,子进程会变为僵尸进程

如果父进程先退出,而子进程不退出会怎么样呢??

cpp 复制代码
#include<stdio.h>
#include<unistd.h>
#include<stdlib.h>
int main()
{
  pid_t id=fork();
  if(id > 0)//正常为子进程
  {
    //childi
     printf("我是父进程,我的pid为%d,我的ppid为%d\n",getpid(),getppid());
     sleep(5);
     exit(1);
   }
   else 
   {
     //parent
     while(1)
     {
       printf("我是子进程,我的pid为%d,我的ppid为%d\n",getpid(),getppid());
       sleep(1);
     }
   }
   return 0;
 }

父进程比子进程先退出,子进程就会变为孤儿进程,同时被1进程收养

如果不被领养的话,子进程会变为僵尸进程,被1收养之后可以被1进程回收。这样就不会造成内存泄漏

父进程先退出

1.这种现象一定会存在 2.子进程一定会被操作系统(1进程)领养 3.如果不领养,那么子进程退出的时候,对应的僵尸进程就没人回收了

4.所以被领养的进程就是孤儿进程 5.如果是前台进程创建了子进程,如果孤儿了,那么它会自动变为后台进程

6. 下章重点

6.1 进程优先级

6.2 进程的竞争性,独立性,并发,并行

相关推荐
gywl5 分钟前
openEuler VM虚拟机操作(期末考试)
linux·服务器·网络·windows·http·centos
青木沐6 分钟前
Jenkins介绍
运维·jenkins
WTT001141 分钟前
2024楚慧杯WP
大数据·运维·网络·安全·web安全·ctf
苹果醋31 小时前
React源码02 - 基础知识 React API 一览
java·运维·spring boot·mysql·nginx
了一li1 小时前
Qt中的QProcess与Boost.Interprocess:实现多进程编程
服务器·数据库·qt
日记跟新中1 小时前
Ubuntu20.04 修改root密码
linux·运维·服务器
唐小旭2 小时前
服务器建立-错误:pyenv环境建立后python版本不对
运维·服务器·python
码农君莫笑2 小时前
信管通低代码信息管理系统应用平台
linux·数据库·windows·低代码·c#·.net·visual studio
明 庭2 小时前
Ubuntu下通过Docker部署NGINX服务器
服务器·ubuntu·docker