[Linux 进程(二)] Linux进程状态

这篇具有很好参考价值的文章主要介绍了[Linux 进程(二)] Linux进程状态。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

[Linux 进程(二)] Linux进程状态,Linux,linux,运维

Linux内核中,进程状态,就是PCB中的一个字段,是PCB中的一个变量,一般是宏定义出的一批数字。
为了弄明白正在运行的进程是什么意思,我们需要知道进程的不同状态。一个进程可以有几个状态(在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 */
};

再配上下面的图,我们看看各进程状态之间的转换:
[Linux 进程(二)] Linux进程状态,Linux,linux,运维

状态的变化,本质就是修改整形变量。
看到这大家可能还是比较懵的,下面我们就来细看每一种状态。
首先我们先看教材上的进程状态,再具体到Linux下的进程状态。

1、进程各状态的概念

1.1 运行状态

每个CPU在系统层面都会维护一个运行队列。(n个CPU就会维护n个运行队列)
[Linux 进程(二)] Linux进程状态,Linux,linux,运维
什么叫做运行状态?
只要在运行队列中的进程,状态都是运行状态。
只要是在运行队列中的进程,它的PCB中状态字段就是R,数据是准备就绪的,只等CPU运行了。

1.2 阻塞状态

进程 = 代码 + PCB(内核数据结构)。而我们的代码中,一定或多或少回访问系统中的某些资源(比如:磁盘、显示器、键盘、网卡等)。
我们下面举例来理解一下阻塞状态,下面是一整个链路,串起来理解:

1、当我们是C/C++代码,代码中有 scanf/cin,需要从键盘中输入时,我们用户就是不输入,键盘上的数据就是没有准备就绪的,这就是进程所要访问的数据没有就绪,即不具备访问条件,导致进程的代码无法向后执行。
2、访问的数据没有就绪,操作系统一定是最先知道的,因为操作系统是一款搞管理的软件,它管理计算机的所有软硬件。操作系统管理硬件,本质也是管理数据,“先描述,再组织”。
3、当进程在CPU中被运行的时候,用户一直不输入,这时访问的数据是没有就绪的,于是PCB就被操作系统从运行队列中放到硬件的等待队列中,PCB中状态字段就被改为 阻塞状态,然后去排队等待。一旦用户输入,数据状态立马就被改为了就绪状态,操作系统再将PCB放入到运行队列(将进程唤醒),并将PCB状态改为运行状态,CPU继续开始运行进程。
[Linux 进程(二)] Linux进程状态,Linux,linux,运维

总结:
1、当PCB不在CPU所维护的运行队列,而在硬件的等待队列中,此时状态就是阻塞状态。
2、进程状态变化的本质:更改PCB中status整数变量; 将PCB链入到不同的列队中。
3、这里的所有过程,只和进程的PCB有关,与进程的数据代码都无关。
4、操作系统中,会有非常多的队列,运行队列、等待硬件的设备等待队列等。

这里我们也就不难想到,平时使用计算机时,启动了非常多的进程后,为什么会那么卡呢?
其实就是操作系统以我们能感知的时间里,将进程的状态不断在改变。

1.3 挂起状态

如果一个进程当前被阻塞了,这个进程等待的资源是没有就绪的,该进程就没有办法被调度。
如果此时,恰好 操作系统内的内存资源严重不足(前提) 了,怎么办?
此时我们阻塞进程的代码和数据就可以先写入磁盘中,等数据就绪后,再拷贝到内存中,这时就叫做 阻塞挂起状态(结果)这里将内存数据置换到磁盘,针对所有的阻塞进程。这个过程虽然慢了点,但是与资源严重不足将要宕机相比,慢点是可以接收的。

这里数据会被置换到swap分区。一般swap分区大小与内存大小差不多大,如果很大,swap分区很难被写满,内存稍微不足,操作系统就会将数据换出到swap分区,频繁的换出就会导致效率变慢。因此设置小点就会倒逼操作系统自己来处理,而不是频繁使用置换算法,提高效率。
当进程被os调度,曾经被置换出去的进程代码和数据,又要被重新加载到内存。
[Linux 进程(二)] Linux进程状态,Linux,linux,运维

具体还有就绪挂起,在运行队列中,但是还没有被调度的进程,代码和数据被换出,等调度的时候再换入,这就是就绪挂起,这样会导致效率变低。

2、Linux进程状态

2.1 运行状态 R

  • R运行状态(running) : 并不意味着进程一定在运行中,它表明进程要么是在运行中要么在运行队列里。
    我们写一段C语言代码来跑一下,看看进程是什么状态。
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>

int main()
{
    while(1)
    {
        printf("Hello Linux, pid:%d\n", getpid());
    	sleep(1);
    }
    
    return 0;
}

我们编译完代码后运行,并用 ps ajx 命令查进程,看看进程状态:

ps ajx | head -1 && ps ajx | grep mytest | grep -v "grep"

[Linux 进程(二)] Linux进程状态,Linux,linux,运维
这里明明是运行着呢,为什么状态是S呢?
这是因为CPU跑代码很快,但是外设显示器的速度很慢,大多时间都是在等待显示器。这就是访问了外设,外设数据没有就绪,进程是阻塞状态。

我们去掉 printf 语句,不让代码去访问外设,直接运行,看到的就是R 运行状态了。
[Linux 进程(二)] Linux进程状态,Linux,linux,运维
[Linux 进程(二)] Linux进程状态,Linux,linux,运维

大家一定还有疑问,我们说的是R与S状态,但是查出来的却是R+与S+,这是怎么回事呢?
+表示的是前台进程的意思,所谓前台进程就是推在前台的,一旦启动我们的bash(命令行解释器)就无法在使用了,前台进程可以使用 ctrl+c 终止掉的。
[Linux 进程(二)] Linux进程状态,Linux,linux,运维

后台进程就是跑在后台的,不影响我们bash的工作(输入命令可以执行),只能使用 kill -9 pid 来终止。后台进程的状态就没有+。
后台进程的启动:./exe &
[Linux 进程(二)] Linux进程状态,Linux,linux,运维

2.2 睡眠状态 S

  • S睡眠状态(sleeping): 意味着进程在等待事件完成浅度睡眠,可以被终止掉,会对外部信号做出响应。(这里的睡眠有时候也叫做可中断睡眠(interruptible sleep))。
    我们写一段C语言代码,编译后运行:
    [Linux 进程(二)] Linux进程状态,Linux,linux,运维
    [Linux 进程(二)] Linux进程状态,Linux,linux,运维
    此时我们不输入,进程就阻塞了,在Linux中具体的状态就是S。
    [Linux 进程(二)] Linux进程状态,Linux,linux,运维
    S状态可以被终止掉,或者可以再换到运行状态。

2.3 深度睡眠 D

  • D磁盘休眠状态(Disk sleep)有时候也叫不可中断睡眠状态(uninterruptible sleep),在这个状态的进程通常会等待IO的结束。
    D状态我们不好演示,我们举例讲一下,什么时候是深度睡眠状态。
    如果我们的进程是往磁盘中做写入操作的时候,写入的数据量很大,这时是磁盘在工作了,进程就休眠了,但是写入成功与否,磁盘还要给进程反馈。恰巧此时内存资源严重不足,置换算法也解决不了时,(Linux下)操作系统是可以杀进程的,它肯定是不会杀掉运行状态的进程,所以它会杀掉睡眠中的进程,此时这个进程被杀掉了。这时磁盘没有将数据写入成功,后面还有进程需要向磁盘写数据,此时磁盘想给进程返回没有成功时,进程被杀掉了,磁盘只好将数据丢弃掉做后面的工作,进程也不知道是否写入成功。如果这是具体的银行10万条存款记录,这就是一次重大事故。
    因此,防止向磁盘写入重要数据时进程被终止掉,就有一个深度睡眠状态 D,深度睡眠状态下的进程是不可以被杀掉的。一般情况下,我们用户要是可以查到D状态,内存就很忙了,也就意味着几乎要宕机。

2.4 停止状态 T

  • T停止状态(stopped): 可以通过发送 SIGSTOP 信号给进程来停止(T)进程。这个被暂停的进程可以通过发送 SIGCONT 信号让进程继续运行。
    我们先来看看一些信号:
    [Linux 进程(二)] Linux进程状态,Linux,linux,运维
    这些数字对应的信号,在Linux内核中其实是宏定义出来的。
    我们以下面的例子来看看,试一下暂停:
    [Linux 进程(二)] Linux进程状态,Linux,linux,运维
    编译后运行:
    [Linux 进程(二)] Linux进程状态,Linux,linux,运维
    我们发送信号让进程暂停了,此时我们发现,bash提示符在闪烁等待我们输入,一暂停进程就被改为后台进程了,不影响我们其他的操作。这时我们想要进程再运行起来,我们做下面的操作:
    [Linux 进程(二)] Linux进程状态,Linux,linux,运维
    这很简单,但是我们为什么要将状态设置为停止状态呢?
    当进程访问软件资源的时候,可能暂时不让进程进行访问,就将进程设置为STOP。
    t 状态,是我们使用gdb调试代码时,追踪程序,遇到断点,进程就暂停了。
    [Linux 进程(二)] Linux进程状态,Linux,linux,运维

这里我们能看到,当我们打了断点后,去运行程序,走到断点处状态变成了t,t表示tracing追踪的意思。
所以,不管是 T/t 都是阻塞状态,这里没有等待硬件资源,而是等待用户的指令,这就叫做 等待软件条件就绪。 因此在具体的os中这些都叫做阻塞状态。

2.5 僵尸状态 Z 与 死亡状态 X

  • X死亡状态(dead):这个状态只是一个返回状态,你不会在任务列表里看到这个状态。
  • Z 僵尸状态(zombie):一个比较特殊的状态。当进程退出并且父进程/OS(使用wait()系统调用,后面讲)没有读取到子进程退出的返回代码时就会产生僵死(尸)进程(父进程要知道子进程把任务完成的怎么样)。
  • 僵死进程会以终止状态保持在进程表(PCB)中,并且会一直在等待父进程读取退出状态代码。
  • 所以,只要子进程退出,父进程还在运行,但父进程没有读取子进程状态,子进程进入Z状态。 如果不及时回收,就会造成内存泄漏(字段会申请资源)。
    我们写一段C语言代码来验证一下 Z 状态,我们父进程不回收子进程:
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>

int main()
{
    pid_t id = fork();
    if(id < 0) return 1;
    else if(id == 0)
    {
        // child
        int cnt = 5;
        while(cnt)
        {
            printf("I am child, run times: %d\n", cnt--);
            sleep(1);
        }
        printf("I am child, dead: %d\n", cnt--);
        exit(2);
    }
    else                                                    
    {
        // father
        while(1)
        {
    		printf("I am father, running any time!\n");
            sleep(1);
	    }

        // 回收操作
    }
 
    return 0;
}

[Linux 进程(二)] Linux进程状态,Linux,linux,运维
父进程没有回收子进程,子进程从S状态变为Z状态,defunct就是死者,死亡的意思。
僵尸进程的危害:

  • 进程的退出状态必须被维持下去,因为他要告诉关心它的进程(父进程),你交给我的任务,我办的怎么样了。可父进程如果一直不读取,那子进程就一直处于Z状态?是的!
  • 维护退出状态本身就是要用数据维护,也属于进程基本信息,所以保存在task_struct(PCB)中,换句话说, Z状态一直不退出, PCB一直都要维护?是的!
  • 那一个父进程创建了很多子进程,就是不回收,是不是就会造成内存资源的浪费?是的!因为数据结构对象本身就要占用内存,想想C中定义一个结构体变量(对象),是要在内存的某个位置进行开辟空间!
  • 内存泄漏 ?是的!

孤儿进程

刚我们讲的是子进程先退出,父进程不回收,导致子进程僵尸状态,那如果子进程不退出,而父进程先退出呢?
我们写一段这样的C语言代码来看看:

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

int main()
{
    pid_t id = fork();
    if(id < 0) return 1;
    else if(id == 0)
    {
        // child
        while(1)
        {
    		printf("I am child ...\n");
            sleep(1);
	    }
    }
    else                                                    
    {
        // father
    	int cnt = 5;
        while(cnt)
        {
            printf("I am father, run times: %d\n", cnt--);
            sleep(1);
        }
        printf("I am father, dead: %d\n", cnt--);
        exit(2);
        // 回收操作
    }
 
    return 0;
}

[Linux 进程(二)] Linux进程状态,Linux,linux,运维
当父进程退出时,是由bash回收的,但是子进程是要被父进程回收的,但是父进程先退出了,子进程要被领养,变成孤儿进程。
一般孤儿进程是要被1号进程领养,如果不领养就无法回收,导致内存泄漏。
那1号进程是谁呢?我们查一下:
[Linux 进程(二)] Linux进程状态,Linux,linux,运维
这里一号进程叫做systemd,它其实就是操作系统。文章来源地址https://www.toymoban.com/news/detail-785328.html

到了这里,关于[Linux 进程(二)] Linux进程状态的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 【Linux】进程概念与进程状态

    在通常的计算机书籍或者课本中对进程概念的描述是这样的 – 进程就是被加载到内存中的程序,或者被运行起来的程序就叫做进程 ;这样说的原因如下: 首先,从 【Linux】计算机的软硬件体系结构 中我们知道,为了提高计算机的整体效率,在数据层面,CPU 不会直接和外设

    2024年02月02日
    浏览(34)
  • 探索Linux下进程状态 | 僵尸进程 | 孤儿进程

    任何进程在运行时都会有自己的状态 下面的状态在kernel源代码里定义: 常见的几种状态: R运行状态(running) : 并不意味着进程一定在运行中,它表明进程要么是在运行中要么在运行队列里。 S睡眠状态(sleeping): 意味着进程在等待事件完成(这里的睡眠有时候也叫做可中断

    2024年04月17日
    浏览(31)
  • 【Linux】详解进程状态之僵尸进程——孤儿进程

    目录 🌞专栏导读 🌛什么是进程 ⭐什么是PCB?  🌛查看进程  🌛如何通过系统调用查看进程PID 🌛fork 🌞认识进程状态 🌛查看进程状态  🌛R状态  ⭐例如: 🌛S状态  🌛D状态  🌛T状态 🌛t状态: 🌛X状态  🌛Z状态 ⭐僵尸进程 ⭐僵尸进程的危害  🌛孤儿进程 🌟作

    2024年02月13日
    浏览(60)
  • 【Linux】—— 详解进程PCB和进程状态

    前言: 在上篇我们已经对有关体系结构的基本知识进行了详细的介绍,接下来我们将进入网络编程的第一个大块—— 有关进程相关的知识!!! 目录 前言 (一) 基本概念 1、描述进程-PCB 2、查看进程 1️⃣通过ps指令  2️⃣通过 /proc 3、通过系统调用获取进程标示符 4、通

    2024年02月09日
    浏览(29)
  • 【Linux】进程查看|fork函数|进程状态

    🦄 个人主页—— 🎐 开着拖拉机回家_Linux,大数据运维-CSDN博客 🎐✨🍁 🪁🍁🪁🍁🪁🍁🪁🍁 🪁🍁🪁🍁🪁🍁🪁 🪁🍁🪁🍁🪁🍁🪁🍁🪁🍁🪁🍁 感谢点赞和关注 ,每天进步一点点!加油! 目录 一、基本概念 1.1 概念提出 1.2 特征 二、描述进程-PCB 2.1 什么是进程

    2024年02月04日
    浏览(29)
  • Linux—进程状态、僵尸进程、孤独进程、优先级

    📘北尘_ :个人主页 🌎个人专栏 :《Linux操作系统》《经典算法试题 》《C++》 《数据结构与算法》 ☀️走在路上,不忘来时的初心 为了弄明白正在运行的进程是什么意思,我们需要知道进程的不同状态。一个进程可以有几个状态(在 Linux内核里,进程有时候也叫做任务)

    2024年02月05日
    浏览(38)
  • 【Linux】进程状态、进程优先级和进程切换

    作者简介:დ旧言~,目前大二,现在学习Java,c,c++,Python等 座右铭:松树千年终是朽,槿花一日自为荣。 目标:了解冯诺依曼体系结构与操作系统,掌握Linux的进程 毒鸡汤:一花凋零荒芜不了整个春天,一次挫折也荒废不了整个人生。 望小伙伴们点赞👍收藏✨加关注哟💕

    2024年02月04日
    浏览(34)
  • 【Linux深入剖析】进程状态---进程僵尸与孤儿

    📙 作者简介 :RO-BERRY 📗 学习方向:致力于C、C++、数据结构、TCP/IP、数据库等等一系列知识 📒 日后方向 : 偏向于CPP开发以及大数据方向,欢迎各位关注,谢谢各位的支持 进程 = taskk_stuct + 可执行程序 进程不是一直在运行的 进程放在cpu上也不会一直运行的 它可能在等待某

    2024年03月18日
    浏览(46)
  • Linux 查看进程状态

    1、进程描述         Linux 系统中时刻运行着很多进程,如果能够合理的管理进程,我们就可以优化系统的性能。 在Linux系统中,有5中常见的进程状态,运行、中断、不可中断、僵死、停止         ps 命令查看 Linux 查看进程  2、每个进程状态所表示的含义 3、进程状态 4、

    2024年02月12日
    浏览(25)
  • Linux进程概念及其状态

    我们的一个程序要运行起来,要先加载到内存当中,如果这个程序已经加载到了内存当中,那么这就叫一个进程。 如图演示一个简单的进程: Windows所打开的一些进程: 我们每次在开机的时候,需要等个几秒钟,这个过程其实就是将操作系统从外设加载内存当中 我们每次使

    2024年02月10日
    浏览(29)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包