进程状态 + 进程优先级切换调度-进程概念(5)

文章目录

  • [Linux 具体的进程状态](#Linux 具体的进程状态)
    • [1. D(disk sleep)状态](#1. D(disk sleep)状态)
    • [2. X(dead)与 Z(zombile)状态](#2. X(dead)与 Z(zombile)状态)
    • [3. 如何模拟验证Z状态](#3. 如何模拟验证Z状态)
    • [4. slab 技术的补充](#4. slab 技术的补充)
  • 进程优先级切换调度(13-0.00.00)
    • [1. 孤儿进程](#1. 孤儿进程)
    • [2. 进程的优先级(13-0.25.00)](#2. 进程的优先级(13-0.25.00))
    • [3. 优先级的具体操作](#3. 优先级的具体操作)

Linux 具体的进程状态

1. D(disk sleep)状态

D状态被称作不可中断休眠或深度睡眠,可能跟磁盘有关系, 这里举个例子进行说明

现在有一个进程要写入100MB数据到磁盘,写入的过程中是有可能中断的,但无论如何,磁盘都会将写入结果返回给进程,进程再告诉用户。而磁盘在拷贝这100MB这份资源期间,进程啥也干不了,它要等磁盘的拷贝结果,此时进程就处于S状态。

但是当系统资源严重不足的时候,操作系统在极端的情况下会采取杀进程的方式释放空间(比如你手机软件有时会直接闪退),那如果这个进程被杀掉了,磁盘手里拿着这100MB的数据不知道该怎么办,跟进程讲也没有啥反应,就只好将其扔掉了,那在系统层面上就丢失了这100MB数据,而且用户还不知道

最为关键的是,操作系统,磁盘,进程,站在各自的角度看哪个都没有错。比如操作系统,它要不杀进程释放资源,那操作系统崩了,全部都得炸。进程它是直接被杀掉的,还是个受害者,没一点办法。磁盘委屈地说,我有啥问题,我都跟进程讲了,让它等我等我

所以此后就出现了D状态,当进程处于D状态时。操作系统就无权杀掉该进程,该进程也有权不对任何杀掉的动作进行响应

因此阻塞状态包括了两种:S与D,那这D状态就只能等它自己醒过来,或者直接重启,还有可能需要断电,才会将该进程直接杀掉

另外再补充一点其它的,输入命令:kill -l,可以查看能发送的信号,目前为止其中用的多是9(kill -9 进程UID),18,19。这三者分别是杀进程,进程继续,进程暂停

2. X(dead)与 Z(zombile)状态

X被称作死亡状态,也就是结束状态。Z被称作僵尸状态(zombile:僵尸),这里还是举个例子来帮助理解

你今天突然遇到一个人倒在了马路边,走上去用手感知,发现这个人没呼吸了,已经死了。这时你赶紧打110,说哪里哪里死了个人,警察来到现场后,会直接将尸体抬走并通知家属吗?

肯定是不会的啊,先封锁现场,让法医进行分析和解剖,直至法医获取到足够的信息,那在这段时间内这个进程所处的状态就是Z状态,就是为了获取进程的退出信息,当法官跟警察说通知家属,把人带走处理后事,这个人才真正死亡,也就是处于X状态

那为啥要存在僵尸状态呢?首先,我们创建子进程的目的是为了让进程完成某种事情的,那最后结果相关的信息(相关信息存储在task_struct中)父进程得知道吧

因此一个子进程要退出了,它并不是一退出就立马将PCB,代码和数据全部释放掉,当一个进程退出时,操作系统可以将这个进程的代码和数据全部释放掉,因为这个进程并不会被调度了

但是它的PCB信息是不能被释放的,必须将自己退出的信息暂时维持处,因为父进程需要从子进程的PCB里获取到子进程退出的结果

在子进程退出之后,父进程获取子进程退出信息之前,此时进程所处的状态就称之为Z状态

3. 如何模拟验证Z状态

创建父,子进程,让子进程在一定程度下直接退出,然后就能查到子进程退出后所处的状态

下面代码中,手动创建一个子进程,让子进程代码循环五次,自动结束。而父进程代码一直处于循环中,此时子进程已经退出了,而父进程仍在运行当中

c 复制代码
int main()
{
    pid_t id = fork();
    if(id == 0)
    {
        //child
        int count = 5;
        while(count)
        {
            printf("我是子进程,我正在运行: %d\n", count);
            sleep(1);
            count--;
        }
    }
    else 
    {
        while(1)
        {
            printf("我是父进程,我正在运行...\n");
            sleep(1);
        }
    }
    return 0;
}

从图片中也能看出,如果父进程一直不管,不获取子进程的退出信息,那么子进程就会一直处于僵尸状态,这样就会造成内存泄漏的问题,这个内存泄漏问题和下面内存泄漏问题造成的原因不同

在咱们写代码时,malloc或new出一片空间,但是忘记及时释放了,此时也会出现内存泄漏问题,那该进程退出了,内存泄漏问题还存不存在呢?不存在

进程一旦退出了,该内存泄漏的问题自然而然地就被解决了,也就是被自动回收了,而上面僵尸状态下的内存泄露的问题是系统层面上的,操作系统做不到回收该PCB

什么样的进程具有内存泄漏问题是比较麻烦的呢,常驻内存的进程 。常驻内存的进程:经常驻扎在内存中的进程,一旦启动该进程,基本上不会退出,一直死循环的那种(比如steam上的那个wallpaper软件)

4. slab 技术的补充

可以构建了一个unuse链表,原先的那个进程从Z状态变成X状态后,那个PCB不是要被释放吗?但是,我可以将要释放的PCB放到这个unuse链表中

等到后面操作系统要再创建(malloc)一个task_struct时,就能直接在这个链表中选择一个task_struct,将结构体里面的成员初始化,那这个task_struct结构体不就能够复用了吗

这样就形成了一个类似于内核当中的数据结构对象的缓存,所以在操作系统内它就可以加速我们创建进程和释放进程的速度,这种技术在Linux内核里叫做slab

进程优先级切换调度(13-0.00.00)

1. 孤儿进程

  • 父进程如果提前退出,那么子进程后退出,子进程进入Z之后,那该如何处理呢?
  • 父进程先退出,子进程就称之为孤儿进程
  • 孤儿进程被1号init/systemd进程领养,当然也要由init/systemd进程回收
c 复制代码
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>

int main()
{
   pid_t id = fork();
   if(id == 0)
   {
       // child
       while(1)
       {
           printf("我是一个子进程, pid: %d, ppid: %d\n", getpid(), getppid());
           sleep(1);
       }
   }
   else
   {
       // father
       int cnt = 5;
       while(cnt)
       {
           printf("我是一个父进程, pid: %d, ppid: %d\n", getpid(), getppid());
           cnt--;
           sleep(1);
       }
   }

   return 0;
}

父子进程关系中,如果父进程先退出,子进程就要被1号(操作系统)进程领养,这个被领养的子进程就叫做孤儿进程

那为什么要领养子进程呢?如果不领养的话,子进程进入僵尸状态之后,就没有父进程帮忙回收,此时就会造成内存泄漏问题

当进程变成孤儿进程,此时的进程就处于后台进程(./cmd &),从图片中也能看到子进程的状态从S+S

当该孤儿进程运行起来之后,命令ctrl + c就无法杀掉,也就是无法杀掉后台进程,同时后台进程能向前台打印消息

只能kill -9 孤儿进程的PID,这样才能将孤儿进程给杀掉

2. 进程的优先级(13-0.25.00)

  • 进程的优先级是什么 :进程得到CPU资源的先后顺序。这里将优先级和权限区分开来,权限是否能得到某种资源,优先级是一定能得到资源,只不过是先后的问题
  • 为什么会存在进程的优先级 :那进程为啥会在CPU上排队呢?因为目标资源稀缺,导致操作系统要通过优先级来确认谁先谁后使用资源的问题

3. 优先级的具体操作

优先级其实也是一种数字(int类型),task_struct的一种属性,值越低,优先级越高,反之优先级越低

基于时间片的分时操作系统,会考虑到公平性,也就是各进程优先级值要相差不大,优先级可能变化,但是变化幅度不能太大

UIDuser id,就是用户ID。人名是给用户看的,操作系统中是看UID,进程启动时会将UID给保存下来,记录这个进程是哪个用户启动的

用户跟操作系统打交道,都是通过进程来进行,用户所有的请求和任何都会转换成进程,被操作系统去调度和执行。所以识别权限并不是去识别用户的,是识别进程和文件之间的权限

带上选项n,显示出用户ID

那系统怎么知道我访问文件的时候,是拥有者,所属组,还是other呢?在Linux系统中,访问任何资源,都是进程去访问,进程就代表用户,OS它会拿着进程的UID依次去匹配文件的拥有者,所属组,other

相关推荐
0wioiw016 分钟前
Ubuntu(④Mysql)
linux·mysql·ubuntu
球求了17 分钟前
Linux 系统入门:环境变量&&虚拟地址空间
linux·运维·服务器·1024程序员节
lkbhua莱克瓦241 小时前
Java基础——常用API2
java·笔记·github·学习方法
java_logo1 小时前
Docker 部署 Rocky Linux 全流程教程
linux·运维·服务器·docker·容器·1024程序员节
丰锋ff1 小时前
英一2016年真题学习笔记
笔记·学习
摇滚侠1 小时前
Spring Boot3零基础教程,Lambda 表达式与函数式接口,笔记95
java·spring boot·笔记
新子y1 小时前
【小白笔记】稀疏数组 (Sparse Array) 在计算机科学中的存储优化问题
笔记
Lynnxiaowen1 小时前
今天我们学习Linux架构keepalived实现LVS代理双击热备
linux·学习·架构·云计算
摇滚侠1 小时前
Spring Boot3零基础教程,Lambda 表达式的使用,笔记96
spring boot·笔记
0wioiw02 小时前
Ubuntu(⑤Redis)
linux·运维·ubuntu