Linux - 进程概念(进程状态、优先级)

news2024/9/20 19:55:41

1.进程状态

操作系统中进程有多种状态模型

三态模型

进程状态分为 就绪态,执行态,阻塞态。

就绪(Ready)状态:指进程已处于准备好运行的状态,即进程已分配到除CPU以外的所有必要资源后,只要再获得CPU,便可立即执行。
执行(Running)状态:指进程已获得CPU,其程序正在执行的状态。
阻塞(Block)状态:正在执行的进程由于发生某事件,暂时无法继续执行的状态,亦即进程的执行受到阻塞。
e780ef3072e842ea19ac728d16e79779.png

五态模型

五态模型中增加了创建和终止状态

 

19e734547a03374809f3aec048c0df26.png

2.Linux下的进程状态

阻塞:进程等待某种资源就绪的过程
进程因为等待某种条件就绪,而导致的一种不推进的状态(进程卡住了),阻塞一定实在等待某种资源。
为什么阻塞?
进程要通过等待的方式,等具体的资源被别人用完之后,在被自己使用。

1be94e97ffa3d13de9e64b5e818c852f.png

挂起:其实也是一种阻塞态,挂起状态后,进程的代码和数据放到了磁盘中,等需要被使用时,再从磁盘中取到内存中

64a670ad525d971465fd465087706e2e.png

 

看看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):这个状态只是一个返回状态,你不会在任务列表里看到这个状态。

R运行状态(running):

进程只要是R状态,就一定是在CPU上运行吗? 不是!

并不直接代表进程再运行,而代表该进程再运行队列中排队。

传统意义上新建态、就绪态在Linux中就是R状态

73f37a6068da01f022f328386e06cde9.png

下面来看一个例子:

代码1:含printf

6dcfbd9b87aa1c5f0776fd363621d0b7.png
474adb43b94e87a477f84daeacaa103c.png

printf 本质就是向外设打印消息,循环打印的过程中外设不会一直处于运行状态,所处理的代码在等待队列中(CPU执行速度非常快)

代码2:不含printf

776ec0c408642e5e37722c6e54716a8c.png
599c6a281eca858ee6a5ce2c4f034bc0.png

没有printf后,CPU就不需要等待外设打印字符,CPU一直处于判断while语句,所以CPU一直处于R状态!

S睡眠状态(sleeping):

可中断休眠,本质就是一种阻塞状态

6a3441fd0d3af5bf748d261842db1ce0.png
415858226e1c3b5fe1cae17c7392084e.png

等待scanf输入,如果一直不输入,就一直阻塞

D磁盘休眠状态(Disk sleep):

有时候也叫不可中断睡眠状态(uninterruptible sleep),在这个状态的进程通常会等待IO的结束。

D状态下,操作系统都无法杀死该模式下的进程

T停止状态(stopped):

可以通过发送 SIGSTOP 信号给进程来停止(T)进程。这个被暂停的进程可以通过发送 SIGCONT 信号让进程继续运行。

5b885c96901400188ab389aeb36134c4.png
kill -19 进程PID //暂停进程
13d910199e7918157fddd2a8344a39da.png
kill -18 进程PID //继续进程
ceeccc0b4344d609bdec736e7222678d.png
f5869ea919770e70490c07029a204bd1.png

为什么Ctrl+C后,还在运行?

Ctrl+C发送了一个SIGINT信号给进程,这个信号通常被用来终止进程。但是,进程在S状态下,是处于可中断状态的,也就是说,如果有一个信号到来,它是可以被打断的,但是如果这个进程正在等待的事件没有发生,它会一直等待下去,即使收到SIGINT信号也无法立即退出。这时候,只能等待这个进程等待的事件发生或者等待被取消,才能使它从S状态中退出。

如果需要强制停止一个S状态的进程,可以使用kill命令,向进程发送SIGKILL信号。但是,这种操作可能会对系统造成一些不良影响,因此应该谨慎使用。

kill -9 PID
6aadbc4fba32215adbafcbde2720e939.png

X死亡状态(dead):

这个状态只是一个返回状态,你不会在任务列表里看到这个状态

3.Z(zombie)-僵尸进程:

僵死状态(Zombies)是一个比较特殊的状态。

当进程退出并且父进程没有读取到子进程退出的返回代码时就会产生僵死(尸)进程

僵死进程会以终止状态保持在进程表中,并且会一直在等待父进程读取退出状态代码。 所以,只要子进程退出,父进程还在运行,但父进程没有读取子进程状态,子进程进入Z状态

举个例子:

一个人突然死亡,普通人不会对现场进行清理,而是报警等警察和法医对该人进行信息的采集,之后才清理现场。

其中,某人充当的角色是进程、警察和法医充当的角色的父进程或者操作系统。

通过代码来模拟僵尸状态的进程


#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
int main()
{
    pid_t id = fork();  //创建进程
    int count = 5;
    while (1)
    {
        if (id == 0)  //子进程
        {
            while (count)  //循环5次
            {
                printf("i am process..child---.pid:%d,ppid:%d\n,count: %d", getpid(), getppi d(), --count);
                sleep(1);
            }
            printf("child quit....\n");
            exit(1);
        }
        else if (id > 0)  //父进程
        {
            printf("i am process..father---pid:%d,ppid:%d\n", getpid(), getppid());
            sleep(1);
        }
    }
    return 0;
}

用以下来查看进程状态

while :; do ps aux |head -1&&ps aux|grep a.out;echo "#######################";sleep 1;done
1ab0c123bfba045f32b2d2b6fa1eef2b.png

僵尸进程的危害

进程的退出状态必须被维持下去,因为他要告诉关心它的进程(父进程),你交给我的任务,我办的怎 么样了。可父进程如果一直不读取,那子进程就一直处于Z状态?是的!
维护退出状态本身就是要用数据维护,也属于进程基本信息,所以保存在task_struct(PCB)中,换句话 说,Z状态一直不退出,PCB一直都要维护?是的!
那一个父进程创建了很多子进程,就是不回收,是不是就会造成内存资源的浪费?是的!因为数据结构 对象本身就要占用内存,想想C中定义一个结构体变量(对象),是要在内存的某个位置进行开辟空 间!
内存泄漏?是的!
如何避免?可以用wait方法和waitpid方法避免,后面文章中讲。

4.孤儿进程

在Linux中,进程的关系主要是父子关系。

一对父子进程中的父进程退出了,子进程还在运行,就会形成孤儿进程。

如果没有进程来回收该子进程的信息,那么会变成僵尸状态,会存在内存泄漏的问题。

为了解决这个问题,该子进程会立即被1号操作系统进程领养。


int main()
{
    pid_t id = fork();
    if (id == 0)
    {
        // child
        while (1)
        {
            printf("我是子进程:pid: %d, ppid: %d\n", getpid(), getppid());
            sleep(1);
        }
    }
    else
    {
        // parent
        int cnt = 10;
        while (1)
        {
            printf("我是父进程:pid: %d, ppid: %d\n", getpid(), getppid());
            sleep(1);
            if (cnt-- <= 0)
                break;
        }
    }
    return 0;
}
b3ff92e4bbd6535d5dfed77834f28e59.png

这里1号进程就是操作系统,也就是说这个进程被操作系统领养了

父进程的僵尸状态未被看见,因为其被其父进程即bash回收

爹嘎了之后,又给自己找了一个爹,PPID为1,也就是操作系统

为什么领养?如果不领养,子进程后续再退出,无人回收,游离的进程多了,占据更多的内存空间。

并且我们可以看到,领养之前,子进程S+前台运行,领养之后,自动由前台变为后台运行,如果想杀掉该进程

  • kill -9 PID

  • killall myproc(进程名称)

5.进程优先级

基本概念

CPU中的资源是有限的,不可能多个进程一起在CPU上运行,利用优先级把进程有效的先后排好,改善了系统的性能。

  • cpu资源分配的先后顺序,就是指进程的优先权(priority)

  • 优先权高的有优先执行权。

  • 还可以把进程运行到指定的CPU上,这样一来,把不重要的进程安排到某个CPU,可以大大改善系统整体性能。

优先级和权限的区别?

优先级是在有权限的前提下,谁先谁后的问题。

查看系统进 进程

在linux或者unix系统中,用ps –l命令则会类似输出以下几个内容:

0c729a63573fa1a5242b62916661654f.png

我们很容易注意到其中的几个重要信息,有下:

UID : 代表执行者的身份 PID : 代表这个进程的代号 PPID :代表这个进程是由哪个进程发展衍生而来的,亦即父进程的代号 PRI :代表这个进程可被执行的优先级,其值越小越早被执行 NI :代表这个进程的nice

PRI and NI

PRI也还是比较好理解的,即进程的优先级,或者通俗点说就是程序被CPU执行的先后顺序,此值越小进程的优先级别越高
那NI呢?就是我们所要说的nice值了,其表示进程可被执行的优先级的修正数值
PRI值越小越快被执行,那么加入nice值后,将会使得PRI变为:PRI(new)=PRI(old)+nice
这样,当nice值为负值的时候,那么该程序将会优先级值将变小,即其优先级会变高,则其越快被执行所以,调整进程优先级,在Linux下,就是调整进程nice值nice其取值范围是-20至19,一共40个级别。

PRI vs NI

需要强调一点的是,进程的nice值不是进程的优先级,他们不是一个概念,但是进程nice值会影响到进程的优先级变化。
可以理解nice值是进程优先级的修正修正数据

用top命令更改已存在进程的nice:

top
进入top后按“r”–>输入进程PID–>输入nice值
b130fbbb8df3b7072c5da7349b1b23f3.png
f4e6e5ff145696f579100dab146cc0a7.png

nice/renice也可以调整优先级

setpriority

其他概念

竞争性: 系统进程数目众多,而CPU资源只有少量,甚至1个,所以进程之间是具有竞争属性的。为了高 效完成任务,更合理竞争相关资源,便具有了优先级 独立性: 多进程运行,需要独享各种资源,多进程运行期间互不干扰
并行: 多个进程在多个CPU下分别,同时进行运行,这称之为并行
并发: 多个进程在一个CPU下采用进程切换的方式,在一段时间之内,让多个进程都得以推进,称之为 并发

 

 

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

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

相关文章

分布式服务高可用实现:复制 | 京东物流技术团队

1. 为什么需要复制 我们可以考虑如下问题&#xff1a; 当数据量、读取或写入负载已经超过了当前服务器的处理能力&#xff0c;如何实现负载均衡&#xff1f; 希望在单台服务器出现故障时仍能继续工作&#xff0c;这该如何实现&#xff1f; 当服务的用户遍布全球&#xff0c;…

迅为iTOP-RK3568开发板是怎么样的呢

迅为iTOP-RK3568开发板是怎么样的呢 CPU方面&#xff1a;iTOP-3568开发板采用瑞芯微RK3568处理器&#xff0c;内部集成了四核64位Cortex-A55处理器。主频高达2.0Ghz&#xff0c;RK809动态调频。集成了双核心架构GPU&#xff0c;ARM G52 2EE、支持OpenGLES1.1/2.0/32OpenCL 2.0…

Simulink仿真模块 - Saturation

目录 说明 实例 模块特性 Saturation将输入信号限制在饱和上界和下界值之间 在仿真库中的位置为:Simulink / 常用模块Simulink / Discontinuities模型为: 说明 Saturation 模块产生输出信号,该信号是在饱和上界和下界值之间的输入信号值。上界和下界由参数 Upper limit 和…

今年嵌入式行情怎么样?

我不了解其它行业可能描述有些片面&#xff0c;但总的来说&#xff0c;我对嵌入式是很看好的&#xff0c;因为你可以感受到你能实际的做出产品而不是类似前端和互联网只是数字数据。 并且嵌入式的学习过程充满乐趣&#xff0c;你可以接触到从沙子到开关管到逻辑门到芯片架构到…

C# Blazor 学习笔记(6):热重置问题解决

文章目录 前言热重置问题描述解决方法演示 总结 前言 我最近在使用Blazor的时候&#xff0c;使用了BootstrapBlazor&#xff08;以下简称BB&#xff09;创建模板的时候&#xff0c;发现热重置无效。经过了一上午的折腾&#xff0c;我终于解决了这个问题。 热重置 问题描述 …

【深度学习环境】安装anaconda、tensorflow、pycharm

目录 1.安装anaconda 2.安装tensorflow-gpu 3.安装pycharm 4.VNC操作 5.安装Pytorch PS: linux下常见的操作&#xff1a; 1.Linux下强制关闭程序&#xff1a; 2.导出环境 2.1.pip导出 2.2.conda导出 2.3.其他 3.windows下的环境安装 & pycharm远程配置 4.bash…

最新版本JDK安装配置及多版本JDK切换

一、JDK安装 1、先说最新的JDK版本&#xff0c;一般指的是JDK 9以及其后的版本&#xff1b; 2、JDK安装分为安装版和免安装版。免安装版必须要配置环境变量才能使用&#xff0c;环境变量配置后面介绍&#xff1b; 3、安装版&#xff1a;最新版本的JDK安装后不需要再配置环境…

SQL语句嵌套查询

嵌套查询的意思是&#xff0c;一个查询语句(select-from-where)查询语句块可以嵌套在另外一个查询块的where子句中&#xff0c;称为嵌套查询。其中外层查询也称为父查询&#xff0c;主查询。内层查询也称子查询&#xff0c;从查询。 嵌套查询的工作方式是&#xff1a;先处理内查…

Cpp学习——动态内存管理

目录 一&#xff0c;new 1.malloc,realloc,calloc的使用不便之处 2.new的好处 3.opreator new 二&#xff0c;delete 1.为什么要有delete? 2.为什么要匹配使用&#xff1f; 一&#xff0c;new 1.malloc,realloc,calloc的使用不便之处 在C语言中&#xff0c;为了申请堆上…

深度学习(33)——CycleGAN(2)

深度学习&#xff08;33&#xff09;——CycleGAN&#xff08;2&#xff09; 完整项目在在这里&#xff1a;欢迎造访 文章目录 深度学习&#xff08;33&#xff09;——CycleGAN&#xff08;2&#xff09;1. Generator2. Discriminator3. fake pool4. loss定义5. 模型参数量6…

无涯教程-Lua - 调试语句

Lua提供了一个调试库&#xff0c;该库提供了所有原始函数供无涯教程创建自己的调试器。即使没有内置的Lua调试器&#xff0c;也有许多针对Lua的调试器&#xff0c;这些调试器由各种开发人员创建&#xff0c;其中许多开源。 下表列出了Lua调试库中可用的函数及其用法。 Sr.No.…

【Spring Boot】请求参数传json对象,后端采用(map)CRUD案例(101)

请求参数传json对象&#xff0c;后端采用&#xff08;map&#xff09;接受的前提条件&#xff1a; 1.Spring Boot 的控制层接受参数采用&#xff1a;RequestBody 2.需要一个Json工具类&#xff0c;将json数据转成Map&#xff1b; 工具类&#xff1a;Json转Map import com.bao…

【MyBatis】MyBatis把空字符串转换成0的问题处理方案(96)

先看问题: Postman入参: MyBatis采用map循环插入: // Mapper接口层void addPar(Param(value "question") Map<String, Object> paramMap);<!-- 新增&#xff1a;参数 --><insert id"addPar" parameterType"map">INSERT IGNO…

DispatcherServlet、拦截器、处理器详解(通俗易懂)

DispatcherServlet、拦截器、处理器详解(通俗易懂) 1.DispatcherServlet ​ 想象一下你去一个大型办公楼寻找特定的办公室。你到达大厅&#xff0c;遇到一个接待员&#xff08;DispatcherServlet&#xff09;。你告诉接待员你要找的办公室&#xff08;请求的URL&#xff09;&…

iOS——Block循环引用

Capturing ‘self’ strongly in this block is likely to lead to a retain cycle 典型的循环引用 self持有了blockblock持有了self(self.name) 这样就形成了self -> block -> self的循环引用 解决办法 强弱共舞 使用 中介者模式 __weak typeof(self) weakSelf sel…

策略模式:优雅地实现可扩展的设计

策略模式&#xff1a;优雅地实现可扩展的设计 摘要&#xff1a; 策略模式是一种常用的设计模式&#xff0c;它可以帮助我们实现可扩展的、灵活的代码结构。本文将通过一个计算器案例来介绍策略模式的概念、使用场景以及如何在实际项目中应用策略模式来提高代码的可维护性和可扩…

海外ASO优化之如何探索竞争对手

查找有关竞争对手应用程序的所有有用信息&#xff0c;并对其进行分析&#xff0c;从而获得有效的见解。 发现与我们应用程序相关的关键词。将他们添加到竞争对手列表中&#xff0c;并通过关键词浏览器工具分析他们的表现。 1、调查竞争对手的 ASO 策略。 搜索查询研究所有国家…

【nginx】源码安装nginx以及手动配置域名ssl证书

安装nginx 下载地址:nginx: download 稳定版 上传源码包到linux目录&#xff0c;如/opt/nginx 安装nginx编译时需要的依赖 yum install -y pcre-devel zlib-devel openssl-devel wget gcc tree vim 编译安装nginx 解压nginx源码安装包&#xff0c;并进入解压后的目录&#…

maven打包时跳过测试

1、命令行 mvn clean install -DskipTests mvn clean -DskipTeststrue install 2、idea跳过 打包时通过idea先进行clean&#xff0c;在进行install&#xff0c;会自动跳过test

机器学习04-数据理解之数据可视化-(基于Pima数据集)

什么是数据可视化? 数据可视化是指通过图表、图形、地图等视觉元素将数据呈现出来的过程。它是将抽象的、复杂的数据转化为直观、易于理解的视觉表达的一种方法。数据可视化的目的是帮助人们更好地理解数据&#xff0c;从中发现模式、趋势、关联和异常&#xff0c;从而作出更明…