当前位置: 首页 > news >正文

【Linux】进程(2)状态

目录

一、冯诺依曼

二、操作系统

三、进程状态

(1)运行状态:进程已获得CPU资源,正在执行指令,是进程生命周期中唯一能直接操作硬件、推进任务的阶段。

(2)阻塞状态:进程因等待特定事件(如打印)主动放弃CPU,但仍保留在内存中,仅不占用CPU资源。等待的事件触发后,进程可直接进入就绪态,等待下一次CPU调度。

(3)挂起状态:挂起是进程的特殊挂起状态,进程会被操作系统从内存换出到外存(如磁盘),完全不占用CPU和内存资源,仅在外存保留进程映像(如PCB等)。


前面我们已经学习了进程的基本概念,在进入进程状态前,我们先了解下冯诺依曼体系结构

一、冯诺依曼

输入设备:包括键盘, 鼠标等

中央处理器(CPU):含有运算器和控制器、寄存器等

输出设备:显示器等

存储器:是指内存(是cpu和外设之间的巨大缓冲区)

cpu只能对内存进行读写,不能访问外设,这也是进程某个状态会发生的原因。

二、操作系统

操作系统:

对下,与硬件交互,管理所有的软硬件资源
对上,为用户程序(应用程序)提供⼀个良好的执行环境

操作系统中不止对进程有着系统的管理,对底层硬件也有管理,类似与对进程的管理,每个外设都有对应的结构体。

我们可以看出进程是在操作系统中,当进程需要被启用时,会先进入cpu就绪队列中,等待cpu调度与执行,运行完还会重新返回到操作系统中。

三、进程状态

这里我们细说三种比较重要的状态:

(1)运行状态:进程已获得CPU资源,正在执行指令,是进程生命周期中唯一能直接操作硬件、推进任务的阶段。

R运行状态(running):运行状态不一定在运行,它表示进程要么是在运行中,要么是在运行队列里。

让程序一直死循环且啥都不打印,就会一直处于运行状态,大家来猜一下子进程是什么状态,子进程一直循环打印自己的信息。

#include <stdio.h> #include <sys/types.h> #include <unistd.h> int main() { int ret = fork(); // printf("%d, ret: %d\n", getpid(), ret); if (ret == 0) { while (1) { printf("I am a child, pid: %d, ppid: %d\n", getpid(), getppid()); sleep(1); } } else if (ret > 0) { printf("I am a father, pid: %d, ppid: %d\n", getpid(), getppid()); while (1) { } } return 0; }

(2)阻塞状态:进程因等待特定事件(如打印)主动放弃CPU,但仍保留在内存中,仅不占用CPU资源。等待的事件触发后,进程可直接进入就绪态,等待下一次CPU调度。

S睡眠(可中断阻塞)状态(sleeping):意味着进程在等待事件完成

没错,子进程就是该状态,为什么呢,都是循环,打印和不打印有什么区别呢?

在上述操作系统中,外设也有对应的数据结构,所以在打印时,cpu会切换其他进程(显示器),而且cpu的运行速度是非常快的,硬件存储时是非常慢的(打印过程),所以我们在查看进程时,总是只能看见子程序在休眠,因为代码执行快,结果出的慢。

D磁盘休眠(不可中断阻塞、不可中断挂起)状态(Disk sleep):有时候也叫不可中断睡眠状态,在这个状态的进程通常会等待IO的结束。(ctrl+c是不能终止的)

当操作系统中内存要满时,会挂起一些进程,如果解决不了,就会杀死一些进程,而有时候会杀死错某些重要的进程,如果在这之前将那些被杀死的程序改成D状态就不会被杀死,相当于免死金牌,OS无法将他们杀死。

(3)挂起状态:挂起是进程的特殊挂起状态,进程会被操作系统从内存换出到外存(如磁盘),完全不占用CPU和内存资源,仅在外存保留进程映像(如PCB等)。

T停止(可中断挂起)状态(stopped):可以通过发送特定信号给进程来停⽌(T)进程。这个被暂停的进程也可以通过发送特定信号让进程继续运行。

这个信号是什么呢?首先kill -9是杀死进程,那他其他的编号对应什么功能呢

SIGSTOP对应的就是停止,SIGCONT对应的就是继续,分别是19、18

X死亡状态(dead):这个状态只是⼀个返回状态,你不会在任务列表里看到这个状态。

Z僵尸状态(zombie):这是一个特殊的状态,当子进程退出时,父进程没有读到子进程退出的返回码时,就会产生僵尸进程。

僵死进程会以终止状态保持在进程表中,并且会⼀直在等待父进程读取退出状态代码。所以会一直占用内存,会产生内存泄漏!

#include <stdio.h> #include <sys/types.h> #include <unistd.h> int main() { int ret = fork(); // printf("%d, ret: %d\n", getpid(), ret); if (ret == 0) { //while (1) //{ // printf("I am a child, pid: %d, ppid: %d\n", getpid(), getppid()); // sleep(1); //} printf("I am a child, pid: %d, ppid: %d\n", getpid(), getppid()); sleep(1); } else if (ret > 0) { printf("I am a father, pid: %d, ppid: %d\n", getpid(), getppid()); while (1) { } } return 0; }

那我们如何去回收退出的子进程,我们需要用到wait()函数。它是系统函数,这里笔者就不给大家做函数解析了,就直接用了。但有一点要提,就是在等待的时候,父进程会进入阻塞状态,等待子进程结束才可以继续运行。


孤儿进程

父进程先于子进程退出的话,子进程就会形成孤儿进程,那这时候子进程退出是由谁来回收,会不会也形成僵尸进程?答案是肯定不会,它会被1号init/systemd进程领养,所以init/systemd进程就会正常进行回收。

前后台运行

这有个小知识点,进程状态后带了+号的是前台运行,没有的是后台运行,./test &启动进程会直接进入后台运行。

前台运行,会占用终端,你无法输入,可以用ctrl+c来终止

后台运行,不会占用终端,你可以输入,但进程会继续在终端打印,ctrl+c终止不了,直接用kill -9 PID来杀死就行了。

这次的内容就到这,我们学习了进程中最常见的状态,其中有于冯诺依曼层次有关的,还有怎么回收子进程,这些都为重要,大家自己写的时候要多留意,谢谢支持。

http://www.jsqmd.com/news/675401/

相关文章:

  • 大模型很热,但怎么用?预算不多也能搞?10大政企AI落地案例,助你收藏学习,开启AI转型之路!
  • AWPortrait-Z人像美化神器:5分钟快速部署,小白也能轻松上手
  • LeetCode 每日一题笔记 日期:2026.04.09 题目:3655.区间乘法查询后的异或二
  • 2026 论文神器榜:10 款 AI 工具让本科写作告别熬夜爆肝
  • vulhub系列-76-02-Breakout(超详细)
  • CSS如何快速获取网页上的标准色值_借助开发者工具的取色器和色彩格式转换功能
  • AI Coding的效能传导:从个体提速到组织进化
  • burpsuite-基础一
  • unity mcp接入 实现一句话生成游戏!
  • SEER‘S EYE 预言家之眼实战:集成至Dify平台构建AI Agent应用
  • Linux命令:ss
  • 从零开始:Spring Boot + MyBatis 搭建后端接口完整教程
  • Linux---信号
  • 线性代数与矩阵运算:AI世界的数学基石——从SVD到特征值分解的实战解析
  • 基于Simulink的轴向磁通电机多物理场耦合仿真​
  • NativeScript APP 开发备忘
  • GitHub 上的 CI/CD 怎么用?从 GitHub Actions 到一条可上线的流水线
  • 学Simulink——基于Simulink的电机参数在线辨识与自适应控制​
  • 我第一次做 OData 后端服务时,真正绊住我的,不是代码,而是 Cloud Foundry 里的这些基础坑
  • yolov8模型训练MOT20数据集 行人多目标跟踪计数数据集的训练及应用 如何根据mot20数据集 来实现行人目标识别,行人追踪,行人的计数
  • Linux命令:ifconfig
  • 在 Word 中,一个公式就能看出你会不会高效排版
  • LumiPixel Canvas Quest与其他开源模型的对比评测
  • 双链表详解
  • Qianfan-OCR入门指南:如何扩展自定义解析模式(如专利权利要求提取)
  • [力扣 105]二叉树前中后序遍历精讲:原理、实现与二叉树还原
  • 如何让全面战争MOD开发从繁琐变得优雅:RPFM的现代化解决方案
  • OpenClaw Web 界面集成教程|通过网页与你的 AI 智能体对话
  • iFakeLocation:你的iOS虚拟定位终极指南,三分钟学会位置模拟
  • 终极免费开源字体Bebas Neue:如何解决现代设计的标题字体难题