Linux篇【5】:Linux 进程概念(三)

news2025/7/22 9:25:08

目录

四、进程状态

4.1、各个操作系统下的进程状态:

4.1.1、进程的运行态:

4.1.2、进程的终止态(退出态):

4.1.3、进程的阻塞态:

4.1.4、进程的挂起态:

4.2、Linux 操作系统下的进程状态:    


四、进程状态

    以后凡是涉及到进程的概念,则必须先想到描述该进程所使用的进程控制块( Linux 系统下为:task_struct ),其实,在操作系统内部( Linux 内核中)进行的进程管理,本质上根本就不在乎进程所对应的在内存中的可执行程序(代码和数据),只在乎描述该进程所使用的进程控制块( Linux 系统下为:task_struct ),所以,前期所阐述的把进程放到 CPU 的运行队列中,本质上就是把描述该进程所使用的进程控制块( Linux 系统下为:task_struct )放到 CPU 的运行队列中去排队、

    进程状态信息在 Linux 内核中就是一个 int 类型的整数(也有可能是 long 类型,总之就是整型),即:int status ,这个 int 整型变量 status 在 Linux 内核中类似于(假设):#define RUN 1 ,#define STOP 2 ,#define SLEEP 3,这个 int 类型的整型变量 status 就存在于进程的所有的属性数据信息中、

    可以通过进程的进程控制块中的所有的属性数据信息找到该进程对应在内存中的可执行程序(代码和数据)所处于内存的位置、


4.1、各个操作系统下的进程状态:

    进程状态反映进程执行过程的变化,这些状态随着进程的执行和外界条件的变化而转换,在三态模型中,进程状态分为三个基本状态,即:运行态,就绪态,阻塞态,在五态模型中,进程分为新建态,终止态,运行态,就绪态,阻塞态、


4.1.1、进程的运行态:

    所谓进程的运行态指的是:当进程所对应的进程控制块( Linux 系统下为:task_struct )在 CPU 的运行队列中或进程正在被 CPU 运行时,此时进程所处的状态就叫做进程的运行态。每个 CPU 中都会存在一个运行队列,而描述某一个进程所使用的进程控制块中的所有的属性数据信息中一定存在部分信息能够找到与该进程对应在内存中的可执行程序(代码和数据),在 CPU 内部存在寄存器,其中保存的就是当前正在被 CPU 运行的进程所对应的进程控制块,并把当前正在被 CPU 运行的进程所对应在内存中的可执行程序(代码和数据)中的起始(入口或 main 函数)代码加载到 CPU 的 PC 指针(程序计数器)中,此时 CPU 就会从该起始(入口或 main 函数)代码处开始往下执行,因此在 CPU 中的运行队列中的任何一个进程控制块所对应的进程,则都属于运行态,运行态代表的就是某一个进程已经准备好了,随时等待被 CPU 调度并运行,或者是某一个进程正在被 CPU 运行,正处于运行态的进程可以分为三种情况:内核运行态,用户运行态,就绪态、


4.1.2、进程的终止态(退出态):

    所谓进程的终止态(退出态)并不是指某一个进程已经被结束(退出)了,而是指该进程还未被结束(退出),只不过永远不会再被 CPU 运行了,随时等待被结束(退出)。当某一个进程永远不会再被CPU 运行时,为什么不直接结束(退出),而是要维护一个终止态呢?,这是因为,结束(退出)进程需要花费时间,此时的操作系统可能很忙,没有办法立马结束(退出)该进程,所以要维护一个终止态,等到操作系统有时间去结束(退出)该进程时,再去结束(退出)该进程、

    某一个进程结束(退出)在理论上就是:将该进程对应在内存中的可执行程序(代码和数据)释放掉,其次再把描述该进程所创建的进程控制块也释放掉、


4.1.3、进程的阻塞态:

    一个进程在申请操作系统中的资源的时候,比如在申请 CPU 资源的时候,还有可能同时在申请操作系统中的其他资源,比如:磁盘资源,网卡资源,显卡资源,显示器资源,声卡或音响资源等等,当我们下载东西时,此时进程在申请操作系统中的 CPU 资源还有网络资源(带宽),磁盘资源,当某一个进程正在申请操作系统中的 CPU 资源,但是无法得到满足时,因为可能还会存在其他的进程同时也在申请操作系统中的 CPU 资源,当前进程(本质上是与该进程对应的进程控制块)需要在 CPU 的运行队列中进行排队,CPU 一般只有一个,最多有两个,由于 CPU 的运算速度非常快,从而使得 CPU 运行队列的周转周期非常短,因此我们看起来好像是所有的进程都正在被CPU 运行,实际上,若 CPU 为单核的话,CPU 只能一次运行一个进程,此时,在 CPU 运行队列中的其他进程所对应的进程控制块只能继续等待、

    如果一个进程还在申请操作系统中的网卡资源,磁盘资源等其他慢设备的资源(这些资源可以是软件资源,也可以是硬件资源)且无法得到满足时,则此时的进程也是需要排队的,此处的排队指的也是该进程所对应的进程制块在进行排队,由此可知,描述某一个进程所使用的进程制块并不是只能在一个双链表(或其它高效的数据结构,但此处主要是指双链表)中,也可以同时存在于另外一个双链表(或其它高效的数据结构,但此处主要是指双链表)中、

    操作系统的核心工作就是先描述,再组织,从而对软硬件资源做管理,所以,对于 CPU 以及其他的慢设备,则都需要被操作系统进行管理,比如在操作系统内部有如下伪代码:

//操作系统的核心工作就是先描述,再组织,从而对软硬件资源做管理,若某一种硬件(网卡,显卡等等)的个
//数只有一个,那么操作系统也是需要对其资源进行管理的,此时也需要对这一种数量只有一个的硬件进行
//描述,但由于这种硬件的数量只有一个,所以也就不涉及用链表或者其他高效的数据结构将多个这种硬件
//组织起来这一说了,只需要对这一种数量只有一个的硬件进行管理即可,由此,操作系统对该硬件的管理变
//成了对该硬件数据的管理、

//1、
//CPU(CPU资源)、
struct cpuinfo
{
  //所有的属性数据信息(包括:CPU的运行/读取速度,CPU的核数,CPU的频率等等)、
  ...
  ...
  //CPU的运行队列(runqueue)、
  task_struct* queue;
}

//注意:
//如果某一个进程正在被 CPU 运行,该进程的目的是往磁盘中写入数据,此时 CPU 就会执行该进程对应在
//内存中的可执行程序中的代码,代码中需要申请使用磁盘资源,但此过程中如果磁盘当前已经没有资源可
//申请时,那应该怎么办,那么此时正在被 CPU 运行的该进程应该怎么办呢,会一直被 CPU 运行吗,答案是
//肯定不会,此时,操作系统会把该正在被 CPU 运行的进程所对应的进程控制块放到磁盘的等待队列中,然
//后让 CPU 去调度并运行正在 CPU 运行队列中的其他的进程控制块所对应的进程,这就是操作系统正在
//执行对进程的管理任务,当磁盘在硬件层面上有资源可被申请时,肯定会通过某种方法告诉操作系统,该方
//式在后期再进行阐述,当操作系统知道了磁盘有资源可以被申请时,操作系统会再把之前放到磁盘等待队
//列中的进程控制块再次放到 CPU 的运行队列中,此时该进程控制块所对应的进程又从进程阻塞态变成了
//运行态,则此时当 CPU 运行该进程控制块所对应的进程时,CPU 就会执行该进程对应在内存中的可执行
//程序中的代码,并且此时可以成功申请到并使用磁盘资源,从而完成该进程的任务,将数据写入磁盘中,
//其次,当磁盘在硬件层面上有资源可被申请时,正在磁盘等待队列中的进程控制块所对应的进程不能直接
//自己去使用磁盘资源,必须要按上述步骤进行操作、 

//由上可知,当该进程的进程控制块在磁盘等待队列中时,该进程控制块所对应的进程对应在内存中的可执
//行程序中的代码就不会再被 CPU 所执行了,此时该进程所处的状态就叫做进程阻塞(是一种临时状态),
//现在,用户(上层)看到的现象就是该进程卡住了、

//总结:
//进程在申请操作系统中的某种资源(一般不是 CPU 资源)时,而该资源没有准备就绪时,该进程所对应的
//进程控制块需要在该资源的等待队列中进行排队,此时该进程对应在内存中的可执行程序中的代码就不会
//再被 CPU 所执行了,此时,该进程所处的状态就是进程阻塞!

//2、
//磁盘(磁盘资源)、
struct disk_div
{
  //所有的属性数据信息、
  ...
  ...
  //磁盘的等待队列(wait_runqueue)、
  task_struct* wait_queue;
}

//3、
//网卡(网卡资源)、
struct net_div
{
  //所有的属性数据信息、
  ...
  ...
  //网卡的等待队列(wait_runqueue)、
  task_struct* wait_queue;
}

...等等、

4.1.4、进程的挂起态:

    当进程处于挂起态时,就决定了他一定不是在申请操作系统中的 CPU 资源,也就意味着该进程正在处于非运行状态,在用户(上层)看来也是该进程卡住了,理论上,每个进程所对应的进程控制块中所存储的所有的属性数据信息的数量与种类是一样的,每个进程不一样,主要体现在每个进程对应在内存中的可执行程序(代码和数据)是不一样的,我们知道,磁盘上的可执行程序(代码和数据)加载到内存,然后,在内存中的可执行程序(代码和数据)再与操作系统描述该进程所使用的进程控制块组合在一起从而形成进程,但是如果磁盘中的可执行程序(代码和数据)数量太多,在他们加载到内存中与操作系统描述这些进程所使用的进程控制块组合在一起形成进程时,从而导致内存空间不足时,操作系统(管理者)应该怎么办?

    操作系统肯定不会割舍它自己的代码(操作系统中的代码),操作系统也会占一部分内存空间,即,操作系统也会把它自己加载到内存中,剩下的内存空间才是给用户使用的,要知道,几乎所以占用内存空间的东西基本上都是以进程的形式出现的,由上可知,操作系统中内存空间变的越来越少,99.99%的原因都是因为进程数量在逐渐变多而导致的、

    若操作系统不解决上述问题的话,轻则导致在磁盘中的一些可执行程序(代码和数据)没有办法加载到内存,进而无法形成进程,严重的情况下,操作系统自己如果再需要内存空间都不够了,基于此,操作系统会帮我们进行辗转腾挪(双向)、

    操作系统会将在申请磁盘,网卡等等非 CPU 资源的等待队列中比较靠后的进程控制块所对应的进程对应在内存中的可执行程序(代码和数据)临时置换到磁盘中的 swap 分区中(若情况十分严重的话,此处这些进程所对应在内存中的进程控制块也会被临时置换到磁盘 swap 分区中,我们暂时不考虑),然后把进程控制块所对应的进程对应在内存中的可执行程序(代码和数据)直接进行释放,除此之外,操作系统自己也会存在一些临时数据会被临时置换到磁盘 swap 分区中,此时这样的进程所处的状态就叫做进程挂起态、

    注意:操作系统不会将在申请 CPU 资源的 CPU 运行队列中比较靠后的进程控制块所对应的进程对应在内存中的可执行程序(代码和数据)临时置换到磁盘中的 swap 分区中,否则导致 CPU 运行速度变的很低、

    在 Windows/Linux 系统下,操作系统默认在磁盘中预留一个与内存匹配的 swap 磁盘分区,该分区就是用来临时存储内存中的进程所对应的在内存中的可执行程序(代码和数据)以及操作系统内的一些临时数据,甚至在部分情况下,也会临时存储内存中的进程所对应的进程控制块,该 swap 磁盘分区是由操作系统进行管理的,一般情况下,该 swap 磁盘分区的大小和内存空间的大小是一样的,比如:假设 swap 磁盘分区大小为4G,则内存空间大小一般也是4G,由此可以理解成,内存空间本质上就是8G,当内存空间不足时,此时磁盘往往会被高频率访问,这是因为操作系统一直在进行辗转腾挪(双向)、

    其实在本质上,当内存空间不足时,操作系统会直接把上述进程对应在内存中的可执行程序(代码和数据)进行释放,并不会临时置换到磁盘 swap 分区,因为磁盘中的 swap 分区的大小也是有限的,只保留上述进程对应在内存中的进程控制块以此保证当再次需要这些进程对应在内存中的可执行程序(代码和数据)时,能够直接找到磁盘非 swap 分区中与被我们直接释放的在内存中的可执行程序(代码和数据)相对应的可执行程序(代码和数据),从而再次把这些磁盘中的可执行程序(代码和数据)加载(拷贝)到内存中,要注意:我们常说的将磁盘中的可执行程序加载到内存中,其实并不是把整个可执行程序都加载到内存中,而是只将该可执行程序中的一部分数据加载到内存中,当内存空间不足时,操作系统会直接把上述进程对应在内存中的可执行程序(代码和数据)进行释放,然后重新调整在磁盘非 swap 分区中与被我们直接释放的在内存中的可执行程序(代码和数据)相对应的可执行程序中的数据页的页表,使得页表指向我们当前可执行程序中的要加载到内存中的数据处,当我们再次需要这些进程对应在内存中的可执行程序(代码和数据)时,直接找到磁盘非 swap 分区中对应的可执行程序中的页表处,使其重新发生缺页中断,再从页表所指的数据处进行局部性加载,把该可执行程序中的所需要的的一部分数据加载到内存中、

    此时,磁盘中的 swap 分区主要是用来临时存放一些不是由内存中进程所产生的临时数据,或者是临时存放一些操作系统本身的临时数据,其次,磁盘 swap 分区存在的原因还有:磁盘 swap 分区中临时存放的一些临时数据(这些临时数据包括:不是由内存中进程所产生的和操作系统本身的)是在一块的,方便操作系统进行辗转腾挪(双向)、


4.2、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 状态:对应于各个操作系统下的进程状态中的进程运行态

//新建会话0:
[HJM@hjmlcc ~]$ ls
Makefile  process.c
[HJM@hjmlcc ~]$ cat process.c
#include<stdio.h>
int main()
{
  while(1)
  {}
  return 0;
}
[HJM@hjmlcc ~]$ make
gcc process.c -o process
[HJM@hjmlcc ~]$ ls
Makefile  process  process.c
[HJM@hjmlcc ~]$ ./process       //可执行程序 process 正在运行、


//新建会话1:
[HJM@hjmlcc ~]$ ls
Makefile  process  process.c
[HJM@hjmlcc ~]$ ps ajx | head -1 && ps ajx | grep 'process' | grep -v grep
 PPID   PID  PGID   SID TTY      TPGID STAT   UID   TIME COMMAND
 8158  9344  9344  8158 pts/2     9344 R+    1002   0:36 ./process         // R+
[HJM@hjmlcc ~]$ 

//此时有关可执行程序 process 所形成的进程对应在内存中的进程控制块加入 CPU 的运行队列中,在此
//之前,该 CPU 的运行队列中还有可能存在其他进程对应在内存中进程控制块,而有关可执行程序 process
//所形成的进程对应在内存中的进程控制块在 CPU 的运行队列中随时等待被 CPU 调度,当 CPU 运行该有
//关可执行程序 process 所形成的进程时,首先是执行该进程对应在内存中的可执行程序中的代码,由于
//该进程对应在内存中的可执行程序中的代码中是死循环,但是该进程对应在内存中的可执行程序中的代码
//并不会一直被 CPU执行,即,该进程并不会一直被 CPU 运行,当过了时间片之后,有关可执行程序 process
//所形成的进程就不会再被 CPU 运行,此时该有关可执行程序 process 所形成的进程对应在内存中的进
//程控制块会再次来到 CPU运行队列的队尾再次进行排队,而此时 CPU 则会继续运行 CPU 运行队列中的
//其他进程、

//时间片是 CPU 分配给 CPU 运行队列中的进程控制块所对应的各个进程的运行时间,每个进程被分配一
//个时间段,称作它的时间片,即该进程允许被 CPU 运行的时间,使 CPU 运行队列中的进程控制块所对应
//的各个进程从表面上看是同时进行的,如果在时间片结束时进程还在被 CPU 运行,则 CPU 将剥夺并分配
//给另一个进程,如果进程在时间片结束前阻塞或结束,则 CPU 当即进行切换,而不会造成 CPU 资源浪费,
//在宏观上:我们可以同时打开多个应用程序,每个应用程序并行不悖,同时运行,但在微观上:由于只有一
//个 CPU ,一次只能运行一个进程,如何处理公平,一种方法就是引入时间片,每个进程轮流被 CPU 运行,
//系统内部有 yield 函数,当时间片到了,OS是在进程的上下文中执行的,OS自己调用 yield 函数,进行
//上下文保护,完成时间片的切换,调度器也会讲进程入队列继续运行的,因为上述死循环没有其他外设
//资源申请的需要,所以就直接继续在 CPU 运行队列中等待了,所以该进程一直处于 R 状态、


//在有关可执行程序 process 所形成的进程中,并没有申请其他外设资源,只申请 CPU 资源,所以不可能
//处于进程阻塞状态,则有关可执行程序 process 所形成的进程所对应的进程控制块,一直会处于 CPU 的
//运行队列中,只不过由于时间片的原因使得该进程所对应的进程控制块在 CPU 的运行队列中的位置是变
//化的,若在 while 循环中做简单的计算,比如:10+10,此时有关可执行程序 process 所形成的进程也没
//有申请其他外设资源,只是申请了 CPU 资源,则有关可执行程序 process 所形成的进程所对应的进程控
//制块也会一直会处于 CPU 的运行队列中,因此,该进程的状态一直都是 R 状态、

二、S 状态:对应于各个操作系统下的进程状态中的进程阻塞态

//新建会话0:
[HJM@hjmlcc ~]$ ls
lcc.c  Makefile  process.c
[HJM@hjmlcc ~]$ cat lcc.c
#include<stdio.h>
#include<unistd.h>
int main()
{
  sleep(1000);
  return 0;
}
[HJM@hjmlcc ~]$ gcc lcc.c
[HJM@hjmlcc ~]$ ls
a.out  lcc.c  Makefile  process.c
[HJM@hjmlcc ~]$ ./a.out             //可执行程序 a.out 正在运行、


//新建会话1:
[HJM@hjmlcc ~]$ ls
a.out  lcc.c  Makefile  process.c
[HJM@hjmlcc ~]$ ps ajx | head -1 && ps ajx | grep 'a.out' | grep -v grep
 PPID   PID  PGID   SID TTY      TPGID STAT   UID   TIME COMMAND
22358 23725 23725 22358 pts/0    23725 S+    1002   0:00 ./a.out             //S+

//由上述可知,在有关可执行程序 a.out 所形成的进程中,当 CPU 正在执行该进程对应在内存中的可执行程
//序中的代码时,即执行语句 sleep(1000); 时,此时该进程所处的状态也是 S 状态,此处在 Linux 操作
//系统下查询的 C 语言的库函数 sleep 就是在申请等待软件资源,我们平常所说的申请等待资源一般指
//的都是申请等待硬件资源、
//新建会话0:
[HJM@hjmlcc ~]$ ls
Makefile  process.c
[HJM@hjmlcc ~]$ cat process.c
#include<stdio.h>
#include<unistd.h>
int main()
{
  while(1)
  {
    printf("I am a process:%d\n",getpid());
    sleep(1);
  }
  return 0;
}
[HJM@hjmlcc ~]$ ls
Makefile  process.c
[HJM@hjmlcc ~]$ make
gcc process.c -o process
[HJM@hjmlcc ~]$ ls
Makefile  process  process.c
[HJM@hjmlcc ~]$ ./process
I am a process:25531
I am a process:25531
I am a process:25531
I am a process:25531
I am a process:25531
I am a process:25531
I am a process:25531
...
...

//新建会话1:
[HJM@hjmlcc ~]$ ls
Makefile  process  process.c
[HJM@hjmlcc ~]$ ps ajx | head -1 && ps ajx | grep 'process' | grep -v grep
 PPID   PID  PGID   SID TTY      TPGID STAT   UID   TIME COMMAND
22358 25531 25531 22358 pts/0    25531 S+    1002   0:00 ./process
[HJM@hjmlcc ~]$ ps ajx | head -1 && ps ajx | grep 'process' | grep -v grep
 PPID   PID  PGID   SID TTY      TPGID STAT   UID   TIME COMMAND
22358 25531 25531 22358 pts/0    25531 S+    1002   0:00 ./process
[HJM@hjmlcc ~]$ ps ajx | head -1 && ps ajx | grep 'process' | grep -v grep
 PPID   PID  PGID   SID TTY      TPGID STAT   UID   TIME COMMAND
22358 25531 25531 22358 pts/0    25531 S+    1002   0:00 ./process
[HJM@hjmlcc ~]$ 

//由上可知,有关可执行程序 process 所形成的进程的状态是 S 状态,这是因为我们的有关可执行程
//序 process 所形成的进程对应在内存中的可执行程序中的代码在被 CPU 运行时,大部分时间都在执
//行 sleep(1); 语句,从而导致该进程处于 S 状态吗?,答案并不是,如下所示:


//新建会话0:
[HJM@hjmlcc ~]$ ls
Makefile  process.c
[HJM@hjmlcc ~]$ cat process.c
#include<stdio.h>
#include<unistd.h>
int main()
{
  while(1)
  {
    printf("I am a process:%d\n",getpid());
  }
  return 0;
}
[HJM@hjmlcc ~]$ ls
Makefile  process.c
[HJM@hjmlcc ~]$ make
gcc process.c -o process
[HJM@hjmlcc ~]$ ls
Makefile  process  process.c
[HJM@hjmlcc ~]$ ./process
I am a process:26084
I am a process:26084
I am a process:26084
I am a process:26084
I am a process:26084
I am a process:26084
...
...


//新建会话1:
[HJM@hjmlcc ~]$ clear
[HJM@hjmlcc ~]$ ls
Makefile  process  process.c
[HJM@hjmlcc ~]$ ps ajx | head -1 && ps ajx | grep 'process' | grep -v grep
 PPID   PID  PGID   SID TTY      TPGID STAT   UID   TIME COMMAND
22358 26084 26084 22358 pts/0    26084 S+    1002   0:00 ./process
[HJM@hjmlcc ~]$ ps ajx | head -1 && ps ajx | grep 'process' | grep -v grep
 PPID   PID  PGID   SID TTY      TPGID STAT   UID   TIME COMMAND
22358 26084 26084 22358 pts/0    26084 S+    1002   0:00 ./process
[HJM@hjmlcc ~]$ ps ajx | head -1 && ps ajx | grep 'process' | grep -v grep
 PPID   PID  PGID   SID TTY      TPGID STAT   UID   TIME COMMAND
22358 26084 26084 22358 pts/0    26084 S+    1002   0:00 ./process
[HJM@hjmlcc ~]$ 

//1、
//由上可知,此时有关可执行程序 process 所形成的进程的状态仍是 S 状态,这是因为,由于有关可执行
//程序 process 所形成的进程对应在内存中的可执行程序中的代码中是死循环,再加上时间片的原因,使
//得该进程对应的进程控制块所在的位置是会发生变化的,不停地在 CPU 运行队列中与显示器资源等待队
//列中进行切换,当该有关可执行程序 process 所形成的进程对应的进程控制块处于显示器资源等待队列
//中时,该进程的状态即为 S 状态,其次,当操作系统把有关可执行程序 process 所形成的进程所对应的
//进程控制块从显示器资源等待队列拿到 CPU 运行队列中排队时,等待 CPU 调度有关可执行程序 process
//所形成的进程所对应的进程控制块,并运行该进程,此时, CPU 会首先执行该进程对应在内存中的可执行
//程序中的代码,并开始将数据从 CPU 加载到内存中,但是由于 CPU 的运算速度比外设存取速度快得多,
//就会导致多个 IO 任务会在内存中堆积,他们也在申请显示器资源,此过程也是进程阻塞态,也是这里的 S
//状态、

//2、
//我们通过 ps 指令查询实时进程的进程状态时,查询到的就是敲回车那一瞬间该进程的状态,由于上述进
//程大部分时间都在排队(包括进程在显示器资源等待队列中排队,以及多个 IO 任务等待从内存刷新到显
//示器中而排队),所以我们查询到的进程状态一般都是 S 状态,出现 R 状态的情况很少,几乎碰不到,其次,
//当某个 IO 任务从内存刷新到显示器的过程中,这个过程也会耗费时间,在此过程中,该进程对应的也是
//进程阻塞状态、

//3、
//上述现象中,虽然看着是在不断的刷屏,其实在此过程中,CPU 也运行了其他的进程,只是速度很快,让我
//们看起来就像该进程就没停止过一样、

在 Linux 操作系统下,S 状态又被叫做 浅度睡眠状态 或 可中断睡眠状态 

浅度睡眠状态:当进程处于 S 状态时,操作系统能够随时把该进程唤醒,我们也能够主动的随时唤醒它,所谓的唤醒就是将该进程的状态改为 R 状态,但是要注意,此处的 S 状态特指的是,进程所对应的进程控制块在非 CPU 资源(非 CPU 资源中非磁盘资源的其他外设资源)的等待队列中排队的时候,我们主动退出(结束)该进程的前提就是先唤醒该进程,由于我们可以随时结束(退出)该进程,所以我们是有能力随时主动唤醒该进程的、

可中断睡眠状态:当该进程处于任意的 S 状态时,我们可以随时主动结束(退出)该进程、

//一:
//新建会话0:
[HJM@hjmlcc ~]$ ls
Makefile  process.c
[HJM@hjmlcc ~]$ cat process.c
#include<stdio.h>
#include<unistd.h>
int main()
{
  while(1)
  {
    printf("I am a process:%d\n",getpid());
    sleep(1);
  }
  return 0;
}
[HJM@hjmlcc ~]$ make
gcc process.c -o process
[HJM@hjmlcc ~]$ ls
Makefile  process  process.c
[HJM@hjmlcc ~]$ ./process
I am a process:29066
I am a process:29066
I am a process:29066
I am a process:29066
I am a process:29066
...
...


//新建会话1:
[HJM@hjmlcc ~]$ ls
Makefile  process  process.c
[HJM@hjmlcc ~]$ ps ajx | head -1 && ps ajx | grep 'process' | grep -v grep
 PPID   PID  PGID   SID TTY      TPGID STAT   UID   TIME COMMAND
22358 29066 29066 22358 pts/0    29066 S+    1002   0:00 ./process
[HJM@hjmlcc ~]$ kill -9 29066
[HJM@hjmlcc ~]$ 


//新建会话0:
...
...
I am a process:29066
I am a process:29066
I am a process:29066
Killed
[HJM@hjmlcc ~]$ 


//二:
//新建会话0:
[HJM@hjmlcc ~]$ ls
lcc.c  Makefile  process  process.c
[HJM@hjmlcc ~]$ cat lcc.c
#include<stdio.h>
#include<unistd.h>
int main()
{
  sleep(100);
  return 0;
}
[HJM@hjmlcc ~]$ gcc lcc.c
[HJM@hjmlcc ~]$ ls
a.out  lcc.c  Makefile  process  process.c
[HJM@hjmlcc ~]$ ./a.out          //可执行程序a.out正在运行、


//新建会话1:
[HJM@hjmlcc ~]$ ls
a.out  lcc.c  Makefile  process  process.c
[HJM@hjmlcc ~]$ ps ajx | head -1 && ps ajx | grep 'a.out' | grep -v grep
 PPID   PID  PGID   SID TTY      TPGID STAT   UID   TIME COMMAND
22358 30172 30172 22358 pts/0    30172 S+    1002   0:00 ./a.out
[HJM@hjmlcc ~]$ kill -9 30172
[HJM@hjmlcc ~]$ 


//新建会话0:
...
...
Killed
[HJM@hjmlcc ~]$ 

三、D 状态:对应于各个操作系统下的进程状态中的进程阻塞态

    在 Linux 操作系统中,D 状态也属于进程阻塞状态,一般而言,当申请非 CPU 资源中,即外设资源中的磁盘资源时,则进程就处于 D 状态,D 状态也叫作深度睡眠状态或磁盘休眠状态,并且 D 状态能够随时被操作系统唤醒,即,当进程所对应的进程控制块在磁盘的等待队列中时,也是进程的阻塞状态,也属于 D 状态,此时该进程可以随时被操作系统唤醒、

    假设现在有一个进程,该进程的目的就是往磁盘中写入数据,此时该进程对应的进程控制块就需要在 CPU 的运行队列中去排队,等待被 CPU 随时调度,当 CPU 运行该进程时,首先会执行该进程对应在内存中的可执行程序中的代码,在执行代码的过程中,发现该进程需要使用磁盘资源,但是,如果此时磁盘资源未准备就绪的话,操作系统会把该正在被 CPU 运行的进程所对应的进程控制块拿到磁盘等待队列中去排队,此时,该进程就是在申请磁盘资源,在各个操作系统中层面上,这就属于进程阻塞状态,但是,在 Linux 操作系统下,这就属于 D 状态,当磁盘资源准备就绪时,磁盘会通过方法告诉操作系统,此时操作系统会再把该进程所对应的进程控制块再拿到 CPU的运行队列中去排队,当 CPU 再次运行该进程时,会接着上次读取到的该进程对应在内存中的可执行程序中的代码继续往下读取,要注意,当 CPU 再次执行完该进程对应在内存中的可执行程序中的代码时,此时该进程就不再处于运行态了,若想要写入磁盘中的数据很多的话,此时在 CPU执行代码但还未全部执行完毕时,CPU 就已经开始把读取到的数据加载到内存中了,此时进程状态还是运行态,只有当 CPU 执行完了所有的代码,并且把在内存中的数据刷新到磁盘中的这个等待过程中才算是运行阻塞状态,这是在时间片未到的情况下进行的考虑,,此时,磁盘资源已经准备就绪,然后 CPU 会先把读取到的数据加载到内存,然后这些数据再被从内存刷新到磁盘中,但是,由于磁盘的存取速度远远比不上CPU的运行速度,所以,会导致在内存中存在很多数据暂时未被从内存中刷新到磁盘上,内存中正在等待被刷新到磁盘中的数据也会被操作系统管理起来,也需要进行排队,所以在磁盘的所有的属性数据信息中,还会存在一个指向另外一个队列的指针,指向一个队列,专门用来管理这些尚未被刷新到磁盘中的数据,当内存中的所有数据被刷新到磁盘中这个过程中,需要花费时间,在这个时间段中,该进程也属于进程阻塞状态,当然也属于 D 状态,并且在该过程中,进程需要等待数据写入磁盘成功或者失败的结果,当在进程等待的过程中,如果内存中进程的数量越来越多的话,操作系统有可能会将该进程设为挂起态,甚至会直接结束(退出)掉,当服务器压力过大,即内存中的进程数量很多的时候,操作系统( Windows 或 Linux 等等),有权利直接结束(退出)某些进程,比如上述这种进程,即,如果上述进程设为 S 状态的话,则有可能会被操作系统直接结束(退出),如果在这个等待的过程中,上述进程被操作系统结束(退出),那么假设往磁盘中写入数据失败,就有可能造成数据丢失,为此,我们必须要保证,在这个等待的时间段中,上述进程一定不能被结束(退出),所以 Linux 操作系统就引出了 D 状态,也属于进程阻塞状态,此时操作系统就无法再把上述进程结束(退出)掉了,D 状态也叫作深度睡眠状态,也叫作不可被中断睡眠,当该进程自己主动退出 D 状态时,该进程才能被结束(退出),其次,当进程还处于 D 状态,若想强行退出(结束)该进程的话,只能关机或者拔电源才可以做到,在有的资料中写到,该 D 状态下的进程只能通过 wake_up 调用函数来使其变成 R 状态、

总结:

    在 Linux 内核中,有两种休眠状态,分别是 S 和 D 状态,这两种状态都属于进程阻塞状态,但是 S 状态是在申请非 CPU 资源,即外设资源中除磁盘资源之外的资源,而 D 状态则是在申请磁盘资源(非 CPU 资源),若想模拟实现 D 状态,可以使用 dd 指令,只做了解即可,若 Linux 操作系统中存在大量的 D 状态进程,此时关机的话,可能会失败,只能强制断电,在此过程中,软件可能会坏掉,比如操作系统,若操作系统中的数据或者是其他用户的数据正在往磁盘中写入,强制断电的话,可能会造成数据丢失,可能就会造成操作系统出现问题,只能重新安装操作系统、


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

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

相关文章

30、Java高级特性——Java API、枚举、包装类、装箱和拆箱

目录 课前先导&#xff1a; 一、Java API 1、API 2、Java API 3、Java API常用包 二、枚举类型 1、枚举 2、枚举类 3、代码演示 3.1 创建枚举类 3.2 创建测试类 4、MyEclipse创建枚举类的快捷方式 三、包装类 1、八大基本数据类型包装类 2、包装类中的构造方…

Java并发编程之可见性分析 volatile

可见性 对于什么是可见性&#xff0c;比较官方的解释就是&#xff1a;一个线程对共享变量的修改&#xff0c;另一个线程能够立刻看到。 说的直白些&#xff0c;就是两个线程共享一个变量&#xff0c;无论哪一个线程修改了这个变量&#xff0c;则另外的一个线程都能够看到上一…

电脑可以通过蓝牙发送文件吗?电脑蓝牙怎么发送文件

蓝牙&#xff08;bluetooth&#xff09;是一种支持设备短距离通信的无线电技术。能在包括移动电话、PDA、无线耳机、笔记本电脑、相关外设等众多设备之间进行无线信息交换。蓝牙技术让数据传输变得更加迅速高效&#xff0c;为无线通信拓宽道路。随着蓝牙技术的发展&#xff0c;…

甘露糖-聚乙二醇-羧酸|mannose-PEG-COOH|羧酸-PEG-甘露糖

甘露糖-聚乙二醇-羧酸|mannose-PEG-COOH|羧酸-PEG-甘露糖 首先合成了二,三分支的甘露糖簇分子.甘露糖经烯丙 苷化,乙酰基保护后,将其烯丙基的双键氧化得到带有羧基连接臂的甘露糖衍生物,然后再分别与1,6-己二胺和三(2-氨乙基)胺进行缩合反应,后脱掉保 护基,得到二分枝甘露糖簇…

Azide-PEG-Thiol,N3-PEG-SH,叠氮-聚乙二醇-巯基可用来制备金纳米颗粒

1、名称 英文&#xff1a;Azide-PEG-Thiol&#xff0c;N3-PEG-SH 中文&#xff1a;叠氮-聚乙二醇-巯基 2、CAS编号&#xff1a;N/A 3、所属分类&#xff1a;Azide PEG Thiol PEG 4、分子量&#xff1a;可定制&#xff0c;5k N3-PEG-SH、20k 叠氮-聚乙二醇-巯基、10k N3-PE…

嵌入式分享合集105

一、智能灯光控制系统&#xff08;基于stm32&#xff09; 带你走进物联网的世界说一个整天方案哦 这次是基于stm32的 当然你可以用esp “智能光照灯”使用STM32作为系统的MCU&#xff0c;由于单片机IO口驱动电流过小&#xff0c;搭配三极管放大电流&#xff0c;从而满足光照强…

全网监控 nginx 部署 zabbix6.0

Zabbix监控 文章目录Zabbix监控一、zabbix6.0部署1、部署zabbix 6.0版本&#xff08;nginxphpzabbix&#xff09;1、nginx配置2、php配置3、mariadb配置二、zabbix配置1、zabbix配置 &#xff08;6.0&#xff09;1、源码安装2、zabbix rpm2、zabbix(5.0安装) -- 补充3、故障汇总…

【Linux】翻山越岭——进程地址空间

文章目录一、是什么写时拷贝二、为什么三、怎么做区域划分和调整一、是什么 回顾我们学习C/C时的地址空间&#xff1a; 有了这个基本框架&#xff0c;我们对于语言的学习更加易于理解&#xff0c;但是地址空间究竟是什么❓我们对其并不了解&#xff0c;是不是内存呢&#xff1…

【创建微服务】创建微服务并使用人人开源代码生成器生成基本代码

创建项目微服务 —— 添加模块 添加依赖 使用 人人开源代码生成器 快速生成 crud 代码 —— https://gitee.com/renrenio 下载导入人人开源项目后&#xff0c;修改 application.yml 文件下的数据库连接配置&#xff1a; 2. 修改 generator.properties 配置文件下的 主路径、包…

CC1101RGPR射频收发器 Low-Power Sub-1GHz 射频收发器

CC1101RGPR射频收发器 Low-Power Sub-1GHz 射频收发器 CC1101RGPR是一种低成本的 sub-1 GHz 收发器专为超低功耗无线应用而设计。该电路主要用于ISM&#xff08;工业、科学和医疗&#xff09;和SRD&#xff08;短程设备&#xff09;频段315、433、868 和 915 MHz&#xff0c;但…

【891. 子序列宽度之和】

来源&#xff1a;力扣&#xff08;LeetCode&#xff09; 描述&#xff1a; 一个序列的 宽度 定义为该序列中最大元素和最小元素的差值。 给你一个整数数组 nums &#xff0c;返回 nums 的所有非空 子序列 的 宽度之和 。由于答案可能非常大&#xff0c;请返回对 109 7 取余 …

UNIAPP实战项目笔记40 设置和地址的页面布局

UNIAPP实战项目笔记40 设置和地址的页面布局 my-config.vue 设置页面布局 具体图片自己替换哈&#xff0c;随便找了个图片的做示例 代码 my-config.vue 页面部分 <template><view class"my-config"><view class"config-item" tap"go…

精益项目管理的流程

我们生活在一个企业家的世界&#xff0c;您可能有许多自己的想法等待实现&#xff0c;但想法在现实中实现是昂贵的。问题是您如何才能获得最大的收益&#xff1f;CEO和管理者如何在追逐梦想和实现目标的同时节省资金&#xff1f;了解初创公司如何进行精益项目管理&#xff0c;它…

第一个汇编程序

第一个汇编程序 文章目录第一个汇编程序1.汇编模拟程序&#xff1a;DOSBox使用2.汇编程序从写出到执行的过程3.程序执行过程跟踪1.汇编模拟程序&#xff1a;DOSBox使用 BOSBox软件常用基本语法&#xff1a; mount c: d:\masn ;挂载磁盘,挂载后用c:切换为C盘才能用debug等工具…

【Java面试八股文宝典之基础篇】备战2023 查缺补漏 你越早准备 越早成功!!!——Day09

大家好&#xff0c;我是陶然同学&#xff0c;软件工程大三明年实习。认识我的朋友们知道&#xff0c;我是科班出身&#xff0c;学的还行&#xff0c;但是对面试掌握不够&#xff0c;所以我将用这100多天更新Java面试题&#x1f643;&#x1f643;。 不敢苟同&#xff0c;相信大…

uni-app入门:WXML列表渲染与条件渲染

1.列表渲染 1.1wx:for 1.2wx:key 2.条件渲染 2.1wx:if 2.2 hidden 正文 WXML全称&#xff1a;wexin markup language,微信标签语言&#xff0c;可以理解为web中的html&#xff0c;今天来讲一下列表渲染&#xff0c;通过几个小案例掌…

艾美捷高纯度 Cholesterol胆固醇相关介绍

胆固醇在体内有着广泛的生理作用&#xff0c;但当其过量时便会导致高胆固醇血症&#xff0c;对机体产生不利的影响。现代研究已发现&#xff0c;动脉粥样硬化、静脉血栓形成与胆石症与高胆固醇血症有密切的相关性。 如果是单纯的胆固醇高则饮食调节是最好的办法&#xff0c;如果…

机器人虚拟仿真工作站考试

总共三个步骤&#xff1a; 创建工作台、加工零件、机器人臂 &#xff01;&#xff01;&#xff01;&#xff01;&#xff01; 一、加工零件的创建 1、先打开sw软件&#xff0c;然后点击零件、创建进入到该软件内&#xff1a; 2、点击前视基础面&#xff08;点击后按esc&#x…

RabbitMQ初步到精通-第四章-RabbitMQ工作模式-WORK

第四章-RabbitMQ工作模式-WORK 1.模式介绍 1.1 work模式 Work模式与前面的Simple模式一致&#xff0c;也是消息经由生产者发到Exchange再到queue再被消费者消费。不同点在于SIMPL模式是一个队列对应的一个消费者&#xff0c;此模式会由一个队列对应两个消费者或大于两个消费者。…

MyBatis的配置文件

日志怎么在mybatis中实现呢 1.添加pom.xml依赖 2.添加logback配置文件 mybatisconfig.xml 引入外部属性资源文件 注意:其中使用的较多的需要设置的为&#xff1a; 引入外部属性资源文件 将数据库的蛇形命名映射为驼峰命名 使用typeAliases标签设置里面的package标签,为…