Linux 进程状态

操作系统学科的进程状态

请添加图片描述

  • 新建态:刚刚创建的进程, 操作系统还未把它加入可执行进程组, 它通常是进程控制块已经创建但还未加载到内存中的新进程。
  • 就绪态:进程做好了准备,只要有机会就开始执行。
  • 阻塞态:进程在某些事件发生前不能执行,如 I/O 操作完成。
  • 执行/运行态:进程正在执行,假设计算机中只有一个处理器,因此最多只有一个进程处于这个状态。
  • 终止/退出态:操作系统从可执行进程组中释放出的进程,要么它自身已停止,要么它因某种原因被取消。

上面的就是操作系统学科中,可能会提到的进程状态!当然你还可能看到诸如:就绪挂起,阻塞挂起等概念!
我们要学习的是一款具体的操作系统:linux 操作系统对进程状态的定义和实现。

linux 进程状态

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

/*
* 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

在 linux 中,进程控制块 task_struct 是用双向链表链接起来的!操作系统维护了一个运行队列,凡是在运行队列中的进程就都处于运行态!被放在操作系统维护的运行队列中的是进程的控制块,即 task_struct,当轮到某个进程的代码被 cpu 执行时,我们能够通过运行队列中的 task_strcut 找到该进程对应的代码和数据!然后开始执行!
在这里插入图片描述
一个正在 cpu 上运行的进程是不是一直要等到该进程的代码执行完毕才把自己从 cpu 上扒下来呢?显然这是不可能的!每一个进程都有一个叫做时间片的概念,当某个进程的时间片消耗完了,就会脱离 cpu,换下一个进程到 cpu 上执行!由一个进程切换到另一个进程,叫做进程切换
linux 中进程的时间片大约是:5~800ms,这就意味着一个进程每次在 cpu 上执行的时间是有限的!加上 cpu 来回地切换进程!我们就能够看到多个进程在同一时间同时运行的现象!


我们能够尝试看到运行状态嘛?因为每个进程在 cpu 上执行的时间都非常短,看到这个状态也是不容易的!

  • 首先我们得学会查看进程的状态嘛!在进程的概念部分我们讲解了查看进程部分属性的方法,其中 ps axj 就能查看进程的状态!

  • 写程序:

    #include<stdio.h>int main()
    {while(1) printf("hello linux\n");return 0;
    }
    //下面是 makefile 文件
    test:test.cgcc -o $@ $^ -std=c99
    .PHONY:cleanclean:
    rm -f test
    

    我们一直在循环打印 “hello linux”。

  • 通过监控脚本查看可执行程序(进程)的状态:

    while :; do ps axj | head -1 && ps axj | grep test | grep -v grep; echo "-------------------------------------------------"; sleep 1; done;
    

    在这里插入图片描述
    我们看到尽管显示器上一直在打印 “hello linux” 但是我们看到的进程状态依旧是:S+,即阻塞状态!
    这个 S+S 的区别就是:

    • S+:加号代表前台进程,S+ 就是这个前台进程正处于阻塞状态。
    • S:表示后台进程正在阻塞中!

    这里前后台的概念就跟手机上的前后台概念差不多!
    我们运行可执行程序的时候加上 & 就能在后台运行啦:./test &
    在这里插入图片描述
    这个时候我们就能看到:S 而不是 S+。在后台运行之后,你发现使用:ctrl + c 结束不掉这个进程了!那是因为 ctrl + c 只能结束前台进程!那要结束该怎么办呢?我们可以使用信号(信号我们后面会详细讲解):

    kill -9 1322154
    

    看上图,这个进程的 pid 是:1322154。我们给 pid 为 1322154 的进程发送九号信号就能将这个进程给杀掉了!

可这并不符合我们的预期哇!我们想看到的是 R 状态哇!怎么办呢?我们尝试将 printf 去掉试试!

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

在这里插入图片描述
我们看到也是成功看到 R 状态啦!这是因为加上 printf 这个进程会等待显示器资源就绪,从而使得进程大部分时间处于阻塞状态!主要是 cpu 执行的速度太快了!

阻塞状态,S

操作系统中为正在运行的进程维护了运行队列!同样也会为正在阻塞的进程维护阻塞队列!一个进程处于阻塞状态的场景很多,比如:等待外设资源就绪(包括,键盘,网卡,鼠标,显示器等等)。
操作系统中的大部分进程都是处于阻塞状态的!


下面的代码中,正在等待键盘的输入,那么这个进程的状态就是阻塞状态呢!

#include<stdio.h>int main()
{int a;scanf("%d", &a);return 0;
}

在这里插入图片描述

深度睡眠/磁盘休眠,D

我们假设一个场景:在很久很久以前,有一个进程 A,正在向磁盘中写入数据!进程 A 正在欢快的写着。突然,操作系统发现,自己的内存空间严重不足了!当他路过进程 A 身边时,发现 A 正在向磁盘中慢吞吞的些数据呢!操作系统看他不顺眼,直接将进程 A 给他杀掉了!(操作系统为了保证自己的正常运行,完全可能杀进程的,类比手机开很多应用程序,操作系统杀后台的例子)。磁盘正写着呢,突然发现这个进程没了,这数据才写道一半呢?怎么办呢?磁盘心想,不完整的数据还是丢了吧!(这是大部分情况的结果!)。
这个时候上层用户发现对自己非常重要的数据没了!一纸诉状,将操作系统,进程,磁盘一并告上了法庭!请听被告的辩词:

  • 操作系统:亲爱的用户,您赋予我管理软硬件资源的权力,为的就是向您提供一个安全,流畅,的运行环境!当时我正处于危机时刻,如果不通过杀死进程来释放内存,我就会崩溃的!导致电脑直接挂掉!
  • 磁盘:我一直在认真完成自己的工作哇,数据写到一半,进程突然没了!我只能将残缺的数据丢掉了!因为我的设定本就是如此!如果我有罪,那么其他的磁盘是不是也同样有罪!
  • 进程:我可是受害者哇!我是被杀掉的,怎么能有罪呢?

如果您是法官大人,您觉得是谁的错呢?显然他们都没有错!
从那以后,当进程正在向磁盘中写数据的时候,他的状态就会被修改为 D 状态,这个 D 状态就是一块免死金牌,操作系统无法杀掉这个进程!
操作系统中 D 状态的进程很短,很少,用户一般都察觉不到。我们无法演示出来 D 状态!
如果真被用户察觉到,那么操作系统肯定要挂了!

暂停状态,T(t)

我们目前认为:Tt 状态没有区别!
在进程状态中的 R 状态中,我们学会了用 kill 命令杀掉一个进程!现在我们再来学习如何使用 kill 命令暂停和运行一个进程!

kill -l #列出所有信号

在这里插入图片描述

(信号部分的原理我们后期会详细讲解,这里学会怎么使用就行啦)这里面有两个信号:SIGSTOPSIGCONT 分别用来暂停,和运行一个暂停的进程!一个进程被暂停之后,我们就能看到 T 状态的进程啦!

#include<stdio.h>
#include<unistd.h>int main()
{for(int i = 0; ; i++){printf("hello linux: %d, pid: %d\n", i, getpid());sleep(1);}return 0;
}

在这里插入图片描述
我们看到,在给 pid 为 1613503 的进程发送 19 号信号之后,进程就暂停下来了,查看这个进程的状态就是 T 状态!
我们在给他发送 18 号信号就能让他从暂停状态变为运行状态!
在这里插入图片描述
T 状态与 S 状态有区别,T 状态可以理解为阻塞状态,只不过 T 状态可能是控制一个进程,或者等待!


T/t 状态有什么运用场景嘛?我们之前是不是学习过 gdb,让程序在代码的某个位置停下来(调试),不就是 T/t 状态的运用嘛!
在这里插入图片描述

终止态,X

终止态的进程是真的就看不到了,一个进程死亡了,被放入垃圾回收的队列中,回收资源!
终止态是一个瞬时状态!

僵尸状态,Z

一个进程退出了,进程的退出信息会被维护一段时间,父进程获取了进程的退出状态之后,该进程由 Z 状态变为 X 状态
进程退出信息被维护的这一段时间,进程就处于 Z 状态!
一般情况下,进程退出的时候,如果父进程没有主动回收子进程的退出消息,子进程会一直处于 Z 状态,子进程相关的资源,尤其是 task_struct 结构体不能被释放,那么子进程的 task_struct 就会一直占用内存资源,造成内存泄漏。

父进程获取子进程退出信息的过程称为进程等待!这个知识点后面会详解!
父进程直接创建了子进程嘛,子进程要退出了,父进程肯定要关心关心撒!父进程创建子进程就是让子进程来办事的嘛!

我们可以写一个代码来验证,子进程退出的时候,父进程不获取子进程的退出状态,那么子进程就会处于僵尸状态的结论:让子进程循环打印 pidppid 三秒之后退出循环,退出循环之后结束子进程。父进程打印自己的 pid

#include<stdio.h>
#include<unistd.h>
#include<stdlib.h>
#include<sys/types.h>int main()
{pid_t id = fork();if(id == 0) //子进程{int cnt = 0;while(1){printf("I am child, pid: %d, ppid: %d\n", getpid(), getppid());sleep(1);cnt++;if(cnt == 3)break;}exit(0);}else if(id > 0){while(1){printf("I am parent, pid: %d\n", getpid());sleep(1);}}else{perror("fork(): ");}return 0;
}

使用监控脚本监控进程的状态:
在这里插入图片描述
我们看到在子进程退出之后,子进程的状态变成了 Z 状态,也就是这个进程变成了僵尸进程
至于怎么获取子进程的退出信息,我们会在进程等待的章节详细讲解!


你有没有想过,如果我们的父进程先退出,结果又是怎么样的呢?

孤儿进程

好的,我们就来写代码看看父进程比子进程先退出是怎么个事儿!
我们让父进程运行三秒之后退出,子进程一直运行,通过监控监本看看会出现什么现象!

#include<stdio.h>
#include<unistd.h>
#include<stdlib.h>
#include<sys/types.h>int main()
{pid_t id = fork();if(id == 0) //子进程{while(1){printf("I am child, pid: %d, ppid: %d\n", getpid(), getppid());sleep(1);}}else if(id > 0){int cnt = 0;while(1){printf("I am parent, pid: %d\n", getpid());sleep(1);cnt++;if(cnt == 3)break;}}else{perror("fork(): ");}return 0;
}

我们看到,父进程退出之后子进程的确一直再跑,只不过子进程的父进程好像发生了变化!
在这里插入图片描述
子进程的父进程变成了 1,我们来看看这个 1 号进程是啥啊!
在这里插入图片描述
一号进程是:systemd,不就是操作系统嘛!
这个现象说明:父进程先于子进程退出,这样的子进程被称为孤儿进程!孤儿进程会被操作系统领养!


为什么操作系统要领养他呢?
因为孤儿进程也要释放资源哇,之前是通过父进程获取子进程的退出状态之后,由操作系统释放资源!父进程提前退出了,那么就直接让操作系统释放不就行了!操作系统有这个能力做到!


bash 进程不是我们自己写的进程的父进程吗? bash 进程能领养孤儿进程嘛?
说到底就是 bash 没有这个能力,即使 bash 进程领养了子进程,但是系统中没有爷爷进程等待孙子进程的逻辑,即使领养了也没用。但是操作系统就不一样了,操作系统是所有进程的管理者,能够直接在内核层面回收!


本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/193764.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Qt+ROS+ubuntu18.04配置教程(带界面)

1. 安装ROS Qt Creator Plug-in 首先安装ROS Qt Creator Plug-in&#xff0c;这其实是一个带有ROS插件的Qt Creator&#xff1a;去下面的网址https://ros-qtc-plugin.readthedocs.io/en/latest/_source/How-to-Install-Users.html#qt-installer-procedure&#xff0c;根据自己…

Java数据结构 之 包装类简单认识泛类

生命不息&#xff0c;奋斗不止 目录 1. 什么是包装类&#xff1f; 1.1 装箱和拆箱 1.2 自动装箱和自动拆箱 2. 什么是泛型 3. 引出泛型 3.1 语法 4 泛型类的使用 4.1 语法 4.2 示例 4.3 类型推导(Type Inference) 5. 裸类型(Raw Type) &#xff08;了解&#xff09…

IPv6是趋势!如何在Windows上禁用或启用IPv6?有3种简单的方法

IPv6是IPv4的一个更加安全、可扩展和可靠的继任者。然而&#xff0c;这种较新的互联网协议与IPv4不向后兼容&#xff0c;并且大多数VPN服务提供商不支持IPv6协议。 Microsoft不建议用户禁用IPv6或其组件&#xff0c;除非他们需要解决网络问题。但是&#xff0c;如果你计划禁用…

MATLAB实战 | 求水仙花数

循环结构的基本思想是重复&#xff0c;即利用计算机运算速度快以及能进行逻辑控制的特点&#xff0c;重复执行某些语句&#xff0c;以满足大量的计算要求。虽然每次循环执行的语句相同&#xff0c;但语句中一些变量的值是变化的&#xff0c;而且当循环到一定次数或满足条件后能…

阿里云服务器活动:免费试用ECS,轻松搭建WordPress博客平台,送午睡毯及猫超卡

阿里云服务器免费试用3个月 &#xff0c;搭建WordPress博客平台&#xff0c;还送午睡毯及猫超卡。活动时间截止至12月8日 网址&#xff1a; 阿里云服务器薅羊毛 送午睡毯

mac M系列芯片安装chatGLM3-6b模型

1 环境安装 1.1 mac安装conda. 下载miniconda&#xff0c;并安装 curl -O https://repo.anaconda.com/miniconda/Miniconda3-latest-MacOSX-arm64.sh sh Miniconda3-latest-MacOSX-arm64.sh1.2 创建虚拟环境并激活 创建名为chatglm3的虚拟环境&#xff0c;python版本为3.10…

Stream API 方法使用总结

文章目录 1.1、Stream介绍1.2、Stream创建对象&#xff08;1&#xff09;empty()方法&#xff08;2&#xff09;of()方法&#xff08;3&#xff09;Arrays.stream()方法&#xff08;4&#xff09;list.stream()方法 1.3、Stream中间方法&#xff08;1&#xff09;filter()方法&…

算法设计与实现--贪心篇

贪心算法 贪心算法是一种在每一步选择中都采取当前状态下最优决策的算法&#xff0c;以期望能够通过一系列局部最优的选择达到全局最优。贪心算法的关键是定义好局部最优的选择&#xff0c;并且不回退&#xff0c;即一旦做出了选择&#xff0c;就不能撤销。 一般来说&#xf…

pybind11教程

pybind11教程 文章目录 pybind11教程1. pybind11简介2. cmake使用pybind11教程3. pybind11的历史 1. pybind11简介 项目的GitHub地址为&#xff1a; pybind11 pybind11 是一个轻量级的头文件库&#xff0c;用于在 Python 和 C 之间进行互操作。它允许 C 代码被 Python 调用&am…

C语言-内存分配

内存分配 1. 引入 int nums[10] {0}; //对int len 10; int nums[len] {0}; //错是因为系统的内存分配原则导致的2. 概述 在程序运行时&#xff0c;系统为了 更好的管理进程中的内存&#xff0c;所以有了 内存分配机制。 分配原则&#xff1a; 2.1 静态分配 静态分配原…

CSS——复合选择器、CSS特性、背景属性、显示模式

1、复合选择器 复合选择器&#xff1a;由两个或多个基础选择器&#xff0c;通过不同的方式组合而成。 作用&#xff1a;更准确、更高效的选择目标元素&#xff08;标签&#xff09; 1.1 后代选择器 后代选择器&#xff1a;选中某元素的后代元素 选择器写法&#xff1a;父选…

Reactor实战,创建一个简单的单线程Reactor(理解了就相当于理解了多线程的Reactor)

单线程Reactor package org.example.utils.echo.single;import java.io.IOException; import java.net.InetSocketAddress; import java.nio.channels.*; import java.util.Iterator; import java.util.Set;public class EchoServerReactor implements Runnable{Selector sele…

Android Studio build.gradle获取项目绝对路径

通过这个字段 ${project.rootProject.projectDir}";如项目根build.gradle中&#xff1a; // Top-level build file where you can add configuration options common to all sub-projects/modules.buildscript {repositories {google()mavenCentral()// jcenter() // kee…

C++基础 -35- string类

string类的格式 string a;如下图&#xff0c;使用string类比常规的字符串处理方便很多 而且需要进行的字符串处理&#xff0c;在类中都能完成 #include "iostream"using namespace std;extern "C" {#include "string.h" }int main() {//c的写…

[Firefly-Linux] RK3568 pca9555芯片驱动详解

文章目录 一、PAC9555 介绍二、ITX-3568JQ PAC9555 使用2.1 原理图2.2 设备树三、RK3568 I2C 介绍四、PAC9555 驱动4.1 介绍4.2 数据结构4.3 驱动分析一、PAC9555 介绍 PAC9555 是一种高性能、低功耗 I/O 扩展芯片,能够提供 16 个 GPIO 通道,每个通道可以单独配置为输入或输…

C语言--求一个十进制整数中1的个数

一.题目描述⭐ 求一个十进制整数中1的个数 比如&#xff1a; 输入:10201 输出&#xff1a;2 &#xff08;这个数字中1的个数是2&#xff09; 二.思路分析⭐ 数字类的问题我们可以用取模&#xff0c;或者取余运算。 首先定义一个计数器&#xff0c;用来统计1的个数。 输入数字…

Python面向对象③:封装【侯小啾python领航班系列(二十一)】

Python面向对象③【侯小啾python领航班系列(二十一)】 大家好,我是博主侯小啾, 🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ�…

关于前端学习的思考-word-wrap和word-break的区别

如上图word-wrap里面的break-word就是按照单词来换行的&#xff0c;空格在前&#xff0c;连字符在后的时候&#xff0c;按照连字符进行换行&#xff0c;那么空格和连字符哪一个拥有优先级呢&#xff1f; 连字符在前&#xff0c;空格在后的时候&#xff0c;还是按照连字符进行换…

分享66个焦点幻灯JS特效,总有一款适合您

分享66个焦点幻灯JS特效&#xff0c;总有一款适合您 66个焦点幻灯JS特效下载链接&#xff1a;https://pan.baidu.com/s/10bqe09IAZt_hbsZlXaxkxw?pwd6666 提取码&#xff1a;6666 Python采集代码下载链接&#xff1a;采集代码.zip - 蓝奏云 学习知识费力气&#xff0c;…

Linux(12):磁盘配额(Quota)与进阶文件系统管理

磁盘配额&#xff08;Quota&#xff09;的应用与实作 Quota 的一般用途&#xff1a; 针对 www server &#xff0c;例如:每个人的网页空间的容量限制&#xff1b; 针对 mail server&#xff0c;例如:每个人的邮件空间限制。 针对 file server&#xff0c;例如:每个人最大的可用…