Linux进程理解【进程状态】

Linux进程理解【进程状态】

进程运行时,进程会被CPU调度,但系统中存在多个进程,进程运行的先后顺序等等该怎么保证呢?OS将进程分成了运行、睡眠、休眠、暂停、死亡等几种状态来对进程进行管理,下面我将带大家学习进程各种状态的应用场景及作用

1. 阻塞和挂起

阻塞

  • 阻塞就是进程因为等待某种条件就绪,而导致的一种不推进的状态
  • 简单来说就是,进程卡住了,原因是在等待某种资源
  • 从数据结构角度来理解,阻塞就是不被调度,这一定是因为进程task_struct结构体需要在某种被OS管理的资源下排队

举个例子,我们在使用到scanf函数时,当我们运行程序,光标会一直到控制台闪烁,实际上此时这个进程就是阻塞状态,它是在等待键盘的输入,也就是在等待键盘输入这一资源

为什么要阻塞呢?

  • 进程要通过等待的方式,等具体的资源被别人用完之后,再被自己使用,阻塞就是进程等待某种资源就绪的过程

挂起

  • 挂起状态就是当CPU资源不足时,OS将数据和代码(进程)交换到磁盘中挂起,此时内存中只有PCB

举个例子,我们在下载软件时,下载这个进程就会被加载到内存中,此时如果突然断网了,就会阻塞(缺少网卡资源),由于这里进程暂时不会被运行,资源放在内存中就会浪费空间,OS就会将代码和数据(进程)暂时存放到磁盘中,等到有网了再从磁盘中拿取,这个过程就是挂起状态,可以说挂起是一种特殊的阻塞状态

2. 进程状态

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运行状态(running): 并不意味着进程一定在运行中,它表明进程要么是在运行中要么在运行队列里
  • S睡眠状态(sleeping): 意味着进程在等待事件完成(这里的睡眠有时候也叫做可中断睡眠)
  • D磁盘休眠状态(Disk sleep):有时候也叫不可中断睡眠状态,在这个状态的进程通常会等待IO的结束
  • T停止状态(stopped): 可以通过发送 SIGSTOP 信号给进程来停止(T)进程。这个被暂停的进程可以通过发送 SIGCONT 信号让进程继续运行
  • X死亡状态(dead):这个状态只是一个返回状态,你不会在任务列表里看到这个状态

2.1 运行状态 R

按照以往的观点,程序一旦运行起来了,那么该程序就是处于运行状态,真的是这样吗?下面我们来看一个例子:

Makefile文件

myproc:mytest.c
	gcc -o myproc mytest.c

.PHONY:monitor
monitor:
	ps ajx | head -1 && ps ajx | grep myproc | grep -v grep 

.PHONY:clean
clean:
	rm -f myproc

这里可以直接将监视指令写入Makefile文件中,使用起来更加方便

下面我们运行监视起来看看现象

通过监视可以观察到此时的进程状态为S+,也就是睡眠状态,+ 号表示当前进程在前台运行

这是为什么呢,难道程序没有运行吗?

  • printf库函数是向外设打印信息,当CPU执行printf库函数时,就需要访问外设,但是这里如果时频繁打印的时候,CPU的运行速度是非常快的,外设和CPU的速度相差太大,导致外设就不一定是就绪的,那么这里就会产生阻塞,这个进程就会被放在对应的外设的结构体队列中排队 。

  • 其实程序运行了,但是我们很难捕捉到,大多数时间,进程都在外设等待队列中排队,导致效果上是休眠状态

这里如果我们去掉printf这一条需要访问外设的语句,进程就不会发生排队阻塞了,此时就可以观察到是运行状态

注意:R状态表示进程在运行,但不一定是在CPU上运行,进程在运行队列中排队也算运行状态

2.2 睡眠状态 S

睡眠状态S的本质就是进程阻塞,表示进程等待某种资源,在上面的测试中已经体现了

进程处于睡眠志状态我们可以通过ctrl + c来终止进程

当进程是在后台运行时,状态表示没有 + 号,此时ctrl + c是无法终止进程的,需要使用kill -9 PID来终止进程

2.3 休眠状态 D

休眠状态D是一种特殊的睡眠状态,又被称为不可中断睡眠状态,休眠状态下的进程是无法终止的,只能等到拿到所需资源,阻塞结束后,进程才会停止休眠状态

休眠状态比较少见,一般会出现于IO阻塞,这个状态的进程通常会等待IO的结束。系统不能出现D状态,出现D状态说明磁盘被占用空间很大,此时这个进程不能删除,一直等到数据被CPU处理完后这个进程才可中断,此时就表示系统离宕机不远了

2.4 暂停状态 T

可以通过指令使进程处于暂停状态T

  • kill -19 PID 暂停指定进程
  • kill -18 PID 恢复进程暂停

使用kill -19 PID 暂停进程

使用kill -18 PID 恢复进程暂停

可以看到此时恢复暂停后,进程状态为S,没有+表示进入了后台睡眠状态,此时使用ctrl+c是无法终止进程的,只能使用kill -9 PID来终止

gdb 中调试代码时,打断点本质上就是 使 进程 在指定行暂停运行,此时 进程 处于 t状态,也就是追踪暂停状态

2.5 死亡状态 X

当进程被终止后,就是处于死亡状态X,无法在任列表中看到这个状态,死亡状态只是一个返回状态

2.6 僵尸状态 Z

僵尸状态Z引入

  • 在多进程执行任务时,如果一个进程退出了,马上就成为了死亡X状态,bash作为父进程,是没有机会拿到退出结果的
  • 为了解决这一问题,Linux下当子进程终止后,不会立即退出,而是会维持一个僵尸Z状态,方便父进程来读取子进程的退出结果

bash有僵尸进程的回收机制,直接在bash环境下终止子进程无法观察到僵尸状态,这里我们可以使用上文中讲到的fork()函数来创建父子进程关系,观察僵尸状态

#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <assert.h>
 
int main()
{
  pid_t ret = fork(); //获取返回值
  assert(ret != -1);  //创建失败的情况
 
  if(ret == 0) //子进程
  {
    while(1)
    {
 
      printf("我是子进程, 我的PID是: %d,PPID是: %d\n", getpid(), getppid());
      sleep(1);
    }
  }
  else if(ret > 0) //父进程
  {
    while(1)
    {
      printf("我是父进程, 我的PID是: %d,PPID是: %d\n", getpid(), getppid());
      sleep(1);
    }                                                      
  }
  else
  {
    printf("进程创建失败!");
  }
 
  return 0;
}

运行监视起来观察现象

这时我们终止子进程,由于子进程没有被回收,此时就是处于僵尸状态

僵尸进程的危害:

  • 僵尸状态一直不退出,PCB需要一直维护,浪费内存资源
  • 僵尸进程如果不被回收,还会导致内存泄漏和标识符占用问题

至于如何避免僵尸进程造成的问题,我会在后续文章详细讲解

3. 孤儿进程

上面了解到了父子进程运行时,当子进程终止后,并不会直接结束,而是处于僵尸状态,方便父进程来读取子进程的结果。

那么如果反过来,父进程先结束,子进程会处于什么状态呢?

下面我们再来启动上面的程序实践一下

然后终止父进程

这里我们观察到,终止父进程后子进程的父进程变成了1号进程

此时的子进程就是孤儿进程

  • 当父进程退出后,子进程会被OS自动领养
  • 子进程的父进程就变成了1号进程,即OS,这个被领养的子进程就是孤儿进程

为什么子进程会被OS领养呢?

  • 如果不被领养,子进程后续再退出,就会变成一个无人回收的僵尸进程,会造成内存泄漏的问题

Linux进程理解—进程状态,到这里就介绍结束了,本篇文章对你由帮助的话,期待大佬们的三连,你们的支持是我最大的动力!

文章有写的不足或是错误的地方,欢迎评论或私信指出,我会在第一时间改正

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

茉莉蜜茶v

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

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

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

打赏作者

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

抵扣说明:

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

余额充值