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

当进程在CPU上跑的时候,并不是一直在运行的。有多个进程的时候会让每个进程都运行一会,进行切换,由于我们人的感官与CPU运行速度差异较大,所以无法发现。

进程状态查看

先简要的介绍两个状态:

阻塞:

进程因为等待某种条件,而导致的一种不推进的状态 -- 进程卡住了 -- 阻塞一定是在等待某种资源(以平时在浏览器上下载文件为例子,当断网时下载在速度变为0kb,进度条不长,这就是在等待网络资源)-- 为什么阻塞?进程要通过等待的方式,等具体的资源被别人用完之后,再被自己使用。阻塞就是进程等待某种资源(磁盘、显卡、网卡等)就绪的过程。

操作系统管理资源与进程的时候都需要有先描述在组织的形式。因此每个进程都有一个假设为task_struct的结构体对象,各种资源也需要有假设为struct_dev的对象来进行管理。

在内核中可以有如下图的结构,当有一个进程不能再CPU上跑时,此时该进程就会将自己的PCB链接在相关资源的尾部进行排队,等待某种资源,这就被称为进程阻塞。

总结:阻塞就是不被调度。---一定是因为当前进程需要等待某种资源 --- 一定是进程task_struct结构体需要被OS管理的资源下排队。

挂起:

系统资源特别紧张,操作系统就会根据算法将闲置的不被调度的进程放入磁盘中,此时这部分的代码与数据就可以被释放,当进程等待的资源就绪的时候,进程需要再被调度,就可以磁盘中重新放入内存中。

下面就以Linux为例子:

先编写一个简单地程序

 #include <stdio.h>
 #include <unistd.h>
 int main()
 {
     while(1)
     {
        printf("正在运行!\n");
        sleep(1);                                                                                                                                   
     }
     return 0;
 }

使用相关命令可以看到状态为S+(休眠状态)。当我们将while中的代码注释掉再次运行就会发现状态变成了下图的情况:

S+为阻塞状态的一种,因为CPU的访问速度与访问外设的速度相差很大,printf的本质就是外设打印消息,当CPU执行printf代码时,如果需要频繁打印,外设不一定是准备就绪的,因此进程就会在外设上进程排队,等到外设就绪,再进行打印工作,所以在使用命令进行查询的时候很大一部反查到的就是S+状态,有很少的情况会是R+状态。

R运行状态

当while中没有printf语句时,当前代码中没有任何访问资源的代码,是一个纯计算的代码,所以在整个进程调度的生命周期中只会调用CPU资源,因此为R+状态,表示该进程在运行队列中排队。

S休眠状态,可中断休眠

当我们有这样的一段代码:

while(1)
{
    int a = 0;
    scanf("%d", &a);
    printf("%d\n", a);                                                                                                                   
}

开始运行的时候就会,等待键盘外设,当我们输入之后,进程就可以继续运行。

T停止状态

使用kill -l可以查看相关的指令:

对于一段正在运行的程序,可以通过kill -19 [PID] 来将其停止:

 

然后可以使用 kill -18 [PID] 指令来继续程序的运行: 

在此时继续查看进程的属性,我们就可以看到其状态由S+变成了S。此时,可以发现使用ctrl+c无法使程序停止。

+表示该进程运行在前台,没有+表示进程运行在后台。若是需要将进程终止就可以使用kill -9 [PID]来杀死程序。

t追踪式停止状态

使用之前学习的gdb调试器就可以在进程属性中查看到t状态。

x死亡/z僵尸状态

在c语言的学习中经常会写return 0;这个表示进程的退出码,使用echo $? 就可以查看对应的退出码。

若是程序的结果有问题就会返回不同的进程退出码:

Linux进程退出时,一般进程不会立即彻底退出,而是要维持一个状态叫做z,也叫做僵尸状态 -- 方便后续父进程os读取子进程退出的退出结果。使用下面的代码

pid_t id = fork();
if (id == 0)
{
    // 子进程
    while (1)
    {
         printf("本进程是子进程PID:%d\n", getpid());
         sleep(2);                                                                                                                      
    }
}    
else if (id > 0)
{
    // 父进程
    while (1)
    {
        printf("本进程是父进程PID:%d\n", getpid());
        sleep(2);
    }
}

 可以发现当在父子进程同时运行时停止子进程,在查看进程属性就变为了Z+

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值