< Linux >:Linux 进程概念 (3)

目录

四、进程状态

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 系统下为: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 操作系统下的进程状态:    

就绪状态就是 R 状态、


        一个进程可以有多个状态, 在 Linux 内核里,进程有时候也叫做任务,下面我们具体谈一下 Linux 操作系统中的进程状态,Linux 操作系统(内核)的源代码当中对于进程的状态有如下定义:
//Linux内核(Kernel)源代码:
/*
* 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             //此处的 'process' 换成 process 也是可以的、
[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 状态(在这个状态下的进程通常会等待 IO 的结束),此时该进程可以随时被操作系统唤醒,D 状态是 Linux 操作系统下特有的状态、

        假设现在有一个进程,该进程的目的就是往磁盘中写入数据,此时该进程对应的进程控制块就需要在 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 状态进程,此时关机的话,可能会失败,只能强制断电,在此过程中,软件可能会坏掉,比如操作系统,若操作系统中的数据或者是其他用户的数据正在往磁盘中写入,强制断电的话,可能会造成数据丢失,可能就会造成操作系统出现问题,只能重新安装操作系统、


评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

脱缰的野驴、

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值