【Linux进程状态】

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档

目录

前言

一、直接谈论Linux的进程状态

看看Linux内核源代码怎么说

1.1、R状态 -----> 进程运行的状态

1.2、S状态 -----> 休眠状态(进程在等待“资源”就绪)

1.3、T状态 -----> 暂停状态

1.4、t状态 ------> 当前的进程因为被追踪而暂停了

1.5、D状态

1.6、僵尸状态(Z)

1.7、死亡状态(X)

二、僵尸进程

下面我们创建一个进程来看一看

僵尸进程危害

三、孤儿进程

下面我们创建一个进程来看一看

四、运行状态

五、阻塞状态

六、挂起状态

七、进程切换的话题

总结



前言

世上有两种耀眼的光芒,一种是正在升起的太阳,一种是正在努力学习编程的你!一个爱学编程的人。各位看官,我衷心的希望这篇博客能对你们有所帮助,同时也希望各位看官能对我的文章给与点评,希望我们能够携手共同促进进步,在编程的道路上越走越远!


提示:以下是本篇文章正文内容,下面案例可供参考

一、直接谈论Linux的进程状态

看看Linux内核源代码怎么说

  • 为了弄明白正在运行的进程是什么意思,我们需要知道进程的不同状态。一个进程可以有几个状态(在 Linux内核里,进程有时候也叫做任务)。
  • 下面的状态在kernel源代码里定义:
 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 */
};

操作系统要更改一个进程的状态,它的原理其实就是更改 task_struct{}内部的状态属性(status)。

1.1、R状态 -----> 进程运行的状态

vim Makefile
testStatus:testStatus.cgcc -o $@ $^ -g
.PHONY:clean
clean:rm -f testStatus

这儿有一个替换方式:

:%s/myprocess/testStatus/  
//将 myprocess替换成 testStatus的可执行程序
vim testStatus.c
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>int main()
{while(1){printf("i am a process,pid:%d\n",getpid());}return 0;
}

我们还可以用shell命令来一直刷新观察

while :; do ps ajx | head -1 && ps ajx | grep testStatus | grep -v grep; sleep 1; done

它其实一直处于一种休眠状态。

我们将打印的代码注释掉,再来看一下程序:

vim testStatus.c
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>int main()
{while(1){//printf("i am a process,pid:%d\n",getpid());}return 0;
}

此时的代码就是一个非常纯粹的循环代码,没有打印。

重新 make 编译一下:

那么为什么我们加上 printf 的代码,就看到了大量的 S(休眠状态)呢?

printf的本质是往显示器上打印;而程序的运行是在千里之外的云服务器上跑;根据冯诺依曼体系结构,显示器是一个外设,所以CPU在跑当前的程序时,把数据写入到我们当前的内存当中,打印数据的顺序:先写入到内存里,再刷新到外设里。可是我们无法保证每次打印的时候,显示器的状态都是就绪的,因为程序是CPU跑的,CPU的运算速度要比显示器本身的速度要快的多,所以进程在被调度的时候,要访问显示器的资源,因为资源要一直在显示器上打,所以大部分时间,相比较CPU来讲,大部分时间,我们对应的进程都在等待我们的设备资源是否就绪。就比如:代码执行到 printf 的时候,CPU是几纳秒,而数据刷新到显示器的时间是几毫秒,其余大部分时间都在等待中,而这等待的时间,就是(S)休眠状态。

1.2、S状态 -----> 休眠状态(进程在等待“资源”就绪)

#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>int main()
{while(1){sleep(10);//printf("i am a process,pid:%d\n",getpid());}return 0;
}

可中断睡眠:处于S睡眠状态,依旧可以随时被外部信息打断,比如:ctrl + c,就醒来了。

进程在运行时 + &(取地址符);那么进程就默认在后端运行。

此时 R 后面就没有 + 了,+ 代表进程是在前端运行的,还是在后端运行的。

1.3、T状态 -----> 暂停状态

T/t :让进程暂停,等待被进一步唤醒。

1.4、t状态 ------> 当前的进程因为被追踪而暂停了

1.5、D状态

  • D:Linux系统比较特有的一种进程状态。
  • 当A进程需要大量的数据写入磁盘的时候,等待磁盘写入数据,此时A进程的状态就是休眠状态,当磁盘写入数据完成或者写入失败的话,都要向A进程汇报情况。
  • 但是有一个场景:系统中内存严重不足时,操作系统有一个特权,Linux操作系统有权力杀掉进程来释放空间。那么此时你的A进程被操作系统杀掉了,用来释放空间,过来3、4秒之后,磁盘已经写入了1GB的数据了,还想要再次写入A进程的数据,但是失败了,失败之后,要汇报情况,可是A进程已经被操作系统杀掉了;此时B进程也要向磁盘写入数据,那么磁盘就去照顾B进程去了,那么已经写入A进程的那1GB数据就丢失了(假如那1GB的数据是转账记录的话,那事故是很严重的),那该怎么办呢?
  • 为了避免这种情况,就可以把等待磁盘数据写入后,需要拿到磁盘返回结果的进程状态,设为D状态。D:不可被杀,深度睡眠,不可中断睡眠。

消除D状态有两种情况:

1、让进程自己醒来;

2、重启,不行的话,就得断电了。

1.6、僵尸状态(Z)

僵尸状态也叫僵死状态,它是在进程在死亡状态之前的状态。当一个进程运行完毕、出现问题或者被杀掉以后,它所占用的内存资源和退出状态没有被它的父进程回收,此时这个进程的状态就称为僵尸状态。

1.7、死亡状态(X)

当一个进程执行结束或者是被操作系统杀掉,它的PCB被操作系统删除,并且对应加载到磁盘上的二进制代码也被删除,此时这个进程就处于死亡状态了。

当一个进程占有内存的所有资源被回收以后,这个进程就处于死亡状态。进程的死亡状态是看不到的,因为只有在回收完成的那一刻才会出现,PCB不存在也就搜索不到这个进程,所以也无法演示。

二、僵尸进程

  • 僵死状态(Zombies)是一个比较特殊的状态。当进程退出并且父进程(使用wait()系统调用,后面讲) 没有读取到子进程退出的返回代码时就会产生僵死(尸)进程。
  • 僵死进程会以终止状态保持在进程表中,并且会一直在等待父进程读取退出状态代码。
  • 所以,只要子进程退出,父进程还在运行,但父进程没有读取子进程状态,子进程进入Z状态。

Linux中的进程退出的时候,会将自己的退出信息保留在自己的PCB当中,如果没有人读取PCB中进程退出的消息,那么进程就会一直不释放;一般会把进程的代码和数据结果释放掉,但是PCB的数据结构不会释放,直到将来对进程进行等待,如果不等待,那么进程会一直处于僵尸状态。如果把进程的退出信息读取了和等待了,那么这个进程才会变成X状态,从而将进程的所有资源全部释放。

一个进程退出的时候,它不会立即退出,而是会现处于一种僵尸状态,如果父进程不会对我们这个进程进行回收或者等待的话,那么对应的进程会一直处于僵尸状态。

下面我们创建一个进程来看一看

#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>int main()
{pid_t id = fork();if(id == 0){// childint cnt = 5;while(cnt){printf("I am child, cnt: %d, pid: %d\n", cnt, getpid());sleep(1);cnt--;}}else{// parentwhile(1){printf("I am parent, running always!, pid: %d\n", getpid());sleep(1);}}return 0;
}

子进程已经运行完毕,但是需要维持自己的退出信息,在自己的进程task_struct会记录自己的退出信息,未来让父进程进行读取。

如果没有父进程读取,僵尸进程会一直存在(内核数据结构task_struct会一直存在),进程的代码和数据会释放。

将来子进程被 waitpid(系统调用接口) 等待方式读取了,那么这个子进程会由Z状态变为X状态,之后由OS来释放。

僵尸进程危害

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

三、孤儿进程

  • 父进程如果提前退出,那么子进程后退出,进入Z之后,那该如何处理呢?
  • 父进程先退出,子进程就称之为“孤儿进程”。
  • 孤儿进程被1号init进程领养,当然要有init进程回收喽。

下面我们创建一个进程来看一看

#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>int main()
{pid_t id = fork();if(id == 0){// childint cnt = 5;while(cnt){printf("I am child, cnt: %d, pid: %d\n", cnt, getpid());sleep(1);//cnt--;}}else{// parentint cnt = 5while(cnt){printf("I am parent, running always!, pid: %d\n", getpid());sleep(1);cnt--;}}return 0;
}

我们已经启动的所有的进程,我们怎么从来没有关心过僵尸进程(内存泄漏)呢?

直接在命令行中启动的进程,它的父进程是bash,bash会自动回收新进程的Z(僵尸进程)。

四、运行状态

操作系统为了合理分配CPU以及各种硬件资源,保证各个进程的正常运行。操作系统会为CPU创建一个进程队列,也为每一个硬件都创建一个等待队列。

而某一个进程处于运行状态本质上就是操作系统将该进程对应的PCB放入CPU的运行队列中,然后再将PCB中维护进程状态的变量修改为相应的值。

PCB里面有进程的各种属性值,以及对应的代码的地址。所以CPU从运行队列中找到PCB取出数据后,可以根据数据得到进程的各种属性值和指令,然后执行相应代码。进程处于运行状态并不意味着该进程此时一定正在被运行,只要该进程处于CPU的运行队列中即可。

注意:CPU是处理数据的速度在纳秒级,运算速度非常快,所以只要进程处于CPU的运行队列中,我们就可以认为该进程正在被运行。

一个进程一旦持有CPU,会一直运行到这个进程结束吗?

不会。CPU基于时间片进行轮转调度的。(Linux不是这样调度的,这只是OS教材调度方法之一)

让多个进程以切换的方式进行调度,在一个时间段内同时得以推进代码,就叫做并发。

每一个CPU都要有一个自己的运行队列,有两个CPU的话,会存在真正意义上的有两个调度队列。任何时刻,都同时有多个进程在真的同时运行,我们叫做并行。

五、阻塞状态

CPU处理数据的速度极快,是我们计算机中的各种硬件处理数据的万倍,比如:一个磁盘或者一个网卡同时只能为一个进程服务,但是在计算机中需要使用这些硬件资源(磁盘等)的进程会有很多。

如果在硬件为一个进程服务时,有其他运行中的进程也需要使用该硬件资源,操作系统就会将该进程的PCB放入硬件的等待队列中,进程会等待硬件来为自己提供服务。

不是只有CPU才有运行队列,各种硬件设备也有自己的等待队列。

由于多个进程需要访问某种硬件,进程PCB在硬件等待队列中等待硬件服务自己的状态就被称为阻塞状态。阻塞状态在本质上就是将进程的PCB从CPU的运行队列中,放入硬件的等待队列中,然后将PCB中维护进程状态的变量也会修改为相应的值。当该进程获得对应的硬件资源服务时,再将该进程放回CPU的运行队列中。

注意:并不是只有等待硬件资源的进程才处于阻塞状态,一个进程等待另一个进程就绪、一个进程等待软件资源就绪等也是阻塞状态。

六、挂起状态

上面我们学习了阻塞状态,处于阻塞状态的进程由于需要等待某种资源,所以它对应的代码和数据在短期内不会被处理(这里的短期指的是对于操作系统而言)。但它们的数据仍储存在内存中,占用存储空间但是不执行,相当于浪费了内存资源。而如果当前操作系统处于高IO(大量向内存输入和向外部设备输出数据)的情况下,可用的内存空间不足,操作系统就会选择性的将这些处于阻塞状态的进程对应的代码和数据转移到磁盘中,从而节省出内存空间。

这种由于内存空间不足,操作系统将在等待资源的进程对应的代码和数据放到磁盘中以节省内存空间的状态就被称为挂起状态。挂起状态不会移动进程的PCB,只会移动进程对应的代码和数据。

挂起并不是释放进程,因为对应的PCB仍然在硬件的等待队列中,当该进程获得对应的资源服务以后,操作系统仍然可以将该进程对应的代码和数据从磁盘加载到内存中来继续运行,其本质是对内存数据的唤入唤出。

七、进程切换的话题

A进程在CPU运行队列中运行的时间片到了之后,A进程会脱离CPU的运行进程;B进程会进入CPU的运行队列中运行,那么比如:A进程在CPU中已经运行到了第50行代码后,时间片到了,退出CPU,当A进程再次进入CPU的时候,是从新开始运行呢?还是接上上回第50行的代码继续运行呢?

CPU里面有一套寄存器,会保留A进程运行的数据,当A进程退出CPU的时候,A进程在CPU中已经运行的数据,将由 task_struct 这个结构体来保存,当A进程再次进入CPU时,数据还会回到寄存器原来的位置,所以A进程会接着第50行继续运行。

进程的切换,最重要的一件事情是:上下文数据的保护和恢复。

CPU内的寄存器:

寄存器本身是硬件,具有数据的存储能力,CPU的寄存器硬件只有一套!!!CPU内部的数据,可以有多套,有几个进程,就有几套和该进程对应的上下文数据。

寄存器 != 寄存器的内容


总结

好了,本篇博客到这里就结束了,如果有更好的观点,请及时留言,我会认真观看并学习。
不积硅步,无以至千里;不积小流,无以成江海。

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

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

相关文章

奇怪的比赛(Python,递归,状态压缩动态规划dp)

目录 前言&#xff1a;题目&#xff1a;思路&#xff1a;递归&#xff1a;代码及详细注释&#xff1a; 状态压缩dp&#xff1a;代码及详细注释&#xff1a; 总结&#xff1a; 前言&#xff1a; 这道题原本是蓝桥上的题&#xff0c;现在搜不到了&#xff0c;网上关于此题的讲解…

Python爬虫:原理与实战

引言 在当今的信息时代&#xff0c;互联网上的数据如同浩瀚的海洋&#xff0c;充满了无尽的宝藏。Python爬虫作为一种高效的数据抓取工具&#xff0c;能够帮助我们轻松地获取这些数据&#xff0c;并进行后续的分析和处理。本文将深入探讨Python爬虫的原理&#xff0c;并结合实战…

kkview远程控制: 内网远程桌面控制软件

内网远程桌面控制软件&#xff1a;高效、安全的远程管理方案 在信息技术日新月异的今天&#xff0c;内网远程桌面控制软件已成为许多企业和个人用户不可或缺的工具。这类软件允许用户通过内部网络&#xff0c;实现对其他计算机的远程访问和控制&#xff0c;从而大大提高工作效…

[Windows] Win11 常用快捷键

文章目录 &#x1f680; [Windows] Win11 常用快捷键&#x1f310; Windows 操作系统&#x1f525; Windows 11 &#x1f310; Windows 11 快捷键概览&#x1f525; 基本快捷键&#x1f525; 窗口快捷键&#x1f525; 功能快捷键 &#x1f4dd; 小结 &#x1f680; [Windows] W…

“技多不压身”是什么意思?看完这篇文章你会明白:有了手艺,走遍天下都不怕!

“技多不压身”是什么意思&#xff1f;看完这篇文章你会明白&#xff1a;有了手艺&#xff0c;走遍天下都不怕&#xff01; 咱们的老祖宗流传一句话&#xff1a;“一招鲜&#xff0c;吃遍天。”这话说得直白&#xff0c;却道出了学一门手艺或技术对于人生的重要性。“李秘书讲…

使用Loadrunner进行性能测试

一、确定性能测试的范围、要求、配置、工具等 明确测试的系统&#xff1a; 本文档主要指的是web应用。 明确测试要求&#xff1a; 用户提出性能测试&#xff0c;例如&#xff0c;网站首页页面响应时间在3S之内&#xff0c;主要的业务操作时间小于10s&#xff0c;支持300用户在…

Android Studio实现内容丰富的安卓宠物用品商店管理系统

获取源码请点击文章末尾QQ名片联系&#xff0c;源码不免费&#xff0c;尊重创作&#xff0c;尊重劳动。 项目编号128 1.开发环境android stuido jdk1.8 eclipse mysql tomcat 2.功能介绍 安卓端&#xff1a; 1.注册登录 2.系统公告 3.宠物社区&#xff08;可发布宠物帖子&#…

this是什么?为什么要改变this?怎么改变 this 指向?

目录 this 是什么&#xff1f; 箭头函数中的 this 为什么要改变 this 指向&#xff1f; 改变 this 指向的三种方法 call(无数个参数) apply(两个参数) bind(无数个参数) this 是什么&#xff1f; 在对象方法中&#xff0c;this 指的是所有者对象&#xff08;方法的拥有者…

提升口才表达能力的重要性与途径

提升口才表达能力的重要性与途径 口才表达能力&#xff0c;即一个人通过口头语言准确、流畅、生动地传达思想、情感和观点的能力&#xff0c;是现代社会中不可或缺的一项基本技能。无论是在职场沟通、人际交往还是公共场合发言&#xff0c;优秀的口才表达能力都能为我们带来诸…

力扣hot100:416.分割等和子集(组合/动态规划/STL问题)

组合数问题 我们思考一下&#xff0c;如果要把数组分割成两个子集&#xff0c;并且两个子集的元素和相等&#xff0c;是否等价于在数组中寻找若干个数使之和等于所有数的一半&#xff1f;是的&#xff01; 因此我们可以想到&#xff0c;两种方式&#xff1a; ①回溯的方式找到t…

vanna:基于RAG的text2sql框架

文章目录 vanna简介及使用vanna的原理vanna的源码理解总结参考资料 vanna简介及使用 vanna是一个开源的利用了RAG的SQL生成python框架&#xff0c;在2024年3月已经有了5.8k的star数。 Vanna is an MIT-licensed open-source Python RAG (Retrieval-Augmented Generation) fram…

探讨大世界游戏的制作流程及技术——大场景制作技术概况篇

接上文&#xff0c;我们接下来了解一下大世界场景制作技术有哪些&#xff0c;本篇旨在给大家过一遍目前业界的做法&#xff0c;能让大家有一个宏观的知识蓝图。实际上&#xff0c;针对不同的游戏类型和美术风格&#xff0c;制作技术在细节上有着非常大的不同&#xff0c;业界目…

HarmonyOS NEXT应用开发—自定义视图实现Tab效果

介绍 本示例介绍使用Text、List等组件&#xff0c;添加点击事件onclick,动画&#xff0c;animationTo实现自定义Tab效果。 效果预览图 使用说明 点击页签进行切换&#xff0c;选中态页签字体放大加粗&#xff0c;颜色由灰变黑&#xff0c;起到强调作用&#xff0c;同时&…

手撕算法-队列实现栈And栈实现队列

手撕算法-队列实现栈And栈实现队列 两个栈实现队列两个队列实现栈包含min函数的栈 两个栈实现队列 分析&#xff1a;转换数据方向&#xff0c;第一个栈写&#xff0c;第二个栈读。 代码&#xff1a; import java.util.*; import java.util.Stack;public class Solution {Sta…

PyCharm中如何使用不同的虚拟环境

1. 简介 有些项目用老的运行环境&#xff0c;而有些项目用新的运行环境&#xff0c;那么我们在运行这些代码&#xff08;比如跑对比实验的时候&#xff09;如何进行切换呢&#xff0c;这时候就可以使用虚拟环境啦 2. 虚拟环境的创建 首先启动Anaconda Prompt 并在其中执行如…

调皮的String及多种玩法(下部)

&#x1f468;‍&#x1f4bb;作者简介&#xff1a;&#x1f468;&#x1f3fb;‍&#x1f393;告别&#xff0c;今天 &#x1f4d4;高质量专栏 &#xff1a;☕java趣味之旅 欢迎&#x1f64f;点赞&#x1f5e3;️评论&#x1f4e5;收藏&#x1f493;关注 &#x1f496;衷心的希…

LeetCode 面试经典150题 26.删除有序数组中的重复项

题目&#xff1a; 给你一个 非严格递增排列 的数组 nums &#xff0c;请你 原地 删除重复出现的元素&#xff0c;使每个元素 只出现一次 &#xff0c;返回删除后数组的新长度。元素的 相对顺序 应该保持 一致 。然后返回 nums 中唯一元素的个数。 考虑 nums 的唯一元素的数量…

C# SM2加解密 ——国密SM2算法

SM2 是国家密码管理局组织制定并提出的椭圆曲线密码算法标准。 本文使用第三方密码库 BouncyCastle 实现 SM2 加解密&#xff0c;使用 NuGet 安装即可&#xff0c;包名&#xff1a;Portable.BouncyCastle&#xff0c;目前最新版本为&#xff1a;1.9.0。 using Org.BouncyCastl…

相机sd卡照片删除后数据恢复,相机sd卡中的照片被删除后如何恢复数据

当我们使用相机拍摄照片时&#xff0c;有时会不小心删除了一些重要的照片。这可能是因为误操作、SD卡故障或者其他原因。无论是珍贵的照片、还是重要的工作文件&#xff0c;被删除后&#xff0c;我们往往会感到焦虑和失望。相机sd卡中的照片被删除后如何恢复数据&#xff1f;幸…

Java项目:54 springboot工资信息管理系统453

作者主页&#xff1a;源码空间codegym 简介&#xff1a;Java领域优质创作者、Java项目、学习资料、技术互助 文中获取源码 项目介绍 本系统的使用角色可以被分为用户和管理员&#xff0c; 用户具有注册、查看信息、留言信息等功能&#xff0c; 管理员具有修改用户信息&#…