【Linux系统编程】第十八弹---进程状态(上)

2024-05-14 14:12

本文主要是介绍【Linux系统编程】第十八弹---进程状态(上),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

  ✨个人主页: 熬夜学编程的小林

💗系列专栏: 【C语言详解】 【数据结构详解】【C++详解】【Linux系统编程】

目录

1、操作系统进程

1.1、进程背景

1.2、进程如何在CPU上运行的?

1.2、进程状态

2、Linux的进程状态

2.1、如何描述进程状态?

2.2、R 和S 运行状态

2.3、T/t 运行状态

2.4、D 运行状态

2.5、僵尸状态(Z)

2.6、死亡状态(X)

总结


1、操作系统进程

1.1、进程背景

         由于Linux是一个多用户,多任务的系统,可以同时运行多个用户的多个程序,就必然会产生很多的进程,而每个进程会有不同的状态。

        进程状态:一个程序被加载到内存变成进程之后,操作系统要对该进程进行管理,即为其创建对应的PCB对象,而进程状态,本质上就是PCB内部的一个整形变量,不同的整形值就对应不同的进程状态。

        常见的进程状态:运行、挂起、阻塞、新建、就绪、等待、挂机、死亡。进程的不同状态本质都是用来满足不同的运行场景的。

1.2、进程如何在CPU上运行的?

CPU在内核上维护了一个运行队列,进行对进程的管理。让进程入队列,本质就是将该进程的task_struct 结构体对象放入运行队列之中。一个CPU就一个运行队列。

1.2、进程状态

1. 运行状态:
进程PCB在运行队列里就是运行状态,不是说这个进程正在运行,才是运行状态。

状态是进程内部的属性,所有的属性在PCB里。

进程不只是占用CPU资源,也有可能随时要外设资源

2. 阻塞状态:
进程不在运行队列之中,进程不能直接被调度,而是在等待外设资源的状态,进程的PCB就被放在硬件的等待队列中。本质是对tack_struct对象放到不同的队列中!

综上,所谓的进程不同的状态,本质是进程在不同的队列之中,等待某种资源

3. 挂起状态:
如果系统中存在许多进程,进程短期内不会被调度,代码和数据在短期内不会被执行,此时如果内存空间不足,操作系统就可以把代码和数据暂时保存到磁盘上,节省一部分空间,该进程暂时被挂起了,这就是挂起状态。

对于阻塞状态和挂起状态,阻塞不一定挂起,挂起一定是阻塞。

2、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 */
};

2.1、如何描述进程状态?

进程状态实质是结构体task_struct内部的一个属性。通过宏定义的方式进行描述以及更改进程状态。

例如:

#define RUN 1
#define SLEEP 2  // 用数字表示进程意思
#define STOP 3struct task_struct
{// 内部的一个属性int status;
}struct task_struct process1; //创建进程
process1.status=RUN;//设置进程状态

补充:vim替换

:%s/name1/name2/   #  name2替换掉name1   在命令模式中

2.2、R 和S 运行状态

R (running): 进程运行的状态 。

S (sleeping): 休眠状态,进程在等待 “资源” 就绪,可中断睡眠。

通过编写C语言代码就行验证,此处依旧使用makefile工具。

makefile 代码:

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

testStatus.c 代码,测试代码:

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

输入命令./testStatus 运行可执行程序,并使用ps 查看进程信息

查看进程信息

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

通过运行结果我们可以看到,我们的进程一直在运行,但是进程状态是S+状态,按照我们正常的理解在运行的程序不就是R(运行)状态?那为什么这里确实S+状态呢???

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

补充:

./testStatus &  # 在执行可执行程序后面加&符号,为在后台运行,跑起来后面不带+号。+号表示在前台还是后台运行,以什么为参考系后面说。后台运行后面有数字(pid),且ctrl +c 不能中断进程,需用kill -9 pid杀掉进程。

2.3、T/t 运行状态

补充命令 kill :

语法:

kill  [-s <信号名称或者编号>][程序]   或   kill  [-l <信息编号>]

功能:

给指定命令发信号。

常见选项:

-l <信息编号> : 若不加<信息编号>选项,则 -l 参数会列出全部的信息名称。

总共有64个信息编号。前面我们使用了-9杀死进程,下面我们会用到-18(SIGCOUT)进程继续以及-19(SIGSTOP)暂停进程

T(stopped)   :让进程暂停,等待被进一步唤醒。暂停后自动会变成后台。

 下图可以看到细节:从S+状态(前台运行)变成T,再由T状态变成了S状态(后台运行)

 

t (tracing stop) : 当前的进程因为被追踪而暂停了。

我们有没有让进程暂停过???

答案是当然有,在我们调试代码的时候,断点就是让进程暂停。

2.4、D 运行状态

讲解D状态之前我们先讲解一个故事。

★ 一个进程A要将1个G的数据存储到硬盘,根据冯诺依曼体系结构可以知道,本质是把数据从内存交给外设,由于速度差,进程需要等待硬盘资源把数据写入完毕,此时进程处于S状态,又因为操作系统管理进程,当系统整个的内存资源严重不足时,Linux操作系统有权利杀掉进程来释放空间,然后操作系统把A进程杀掉,但是此时B进程要给硬盘写入数据,硬盘需要去照顾B进程,导致A进程写入数据失败了,1GB的数据丢失了,如果这个数据是银行的转账记录,那么可能造成很大的影响。

 ★ 为了避免这种情况,如果进程在等待硬盘资源时,进程需要将自己的状态设为D状态:不可被杀深度睡眠,不可中断睡眠。

 ★ 我们一般不会遇到这种情况,从事系统管理、运维、存储等工作可能会遇到。

D (disk sleep): Linux系统比较特有的一种进程状态,不可被杀,深度睡眠,不可中断睡眠。

杀死D状态的方法:

1、进程自己醒来。

2、重启,重启不行则断电。

2.5、僵尸状态(Z)

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

2.6、死亡状态(X)

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

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

总结


本篇博客就结束啦,谢谢大家的观看,如果公主少年们有好的建议可以留言喔,谢谢大家啦!

这篇关于【Linux系统编程】第十八弹---进程状态(上)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/988959

相关文章

SpringSecurity JWT基于令牌的无状态认证实现

《SpringSecurityJWT基于令牌的无状态认证实现》SpringSecurity中实现基于JWT的无状态认证是一种常见的做法,本文就来介绍一下SpringSecurityJWT基于令牌的无... 目录引言一、JWT基本原理与结构二、Spring Security JWT依赖配置三、JWT令牌生成与

Linux ls命令操作详解

《Linuxls命令操作详解》通过ls命令,我们可以查看指定目录下的文件和子目录,并结合不同的选项获取详细的文件信息,如权限、大小、修改时间等,:本文主要介绍Linuxls命令详解,需要的朋友可... 目录1. 命令简介2. 命令的基本语法和用法2.1 语法格式2.2 使用示例2.2.1 列出当前目录下的文

利用Python快速搭建Markdown笔记发布系统

《利用Python快速搭建Markdown笔记发布系统》这篇文章主要为大家详细介绍了使用Python生态的成熟工具,在30分钟内搭建一个支持Markdown渲染、分类标签、全文搜索的私有化知识发布系统... 目录引言:为什么要自建知识博客一、技术选型:极简主义开发栈二、系统架构设计三、核心代码实现(分步解析

关于WebSocket协议状态码解析

《关于WebSocket协议状态码解析》:本文主要介绍关于WebSocket协议状态码的使用方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录WebSocket协议状态码解析1. 引言2. WebSocket协议状态码概述3. WebSocket协议状态码详解3

Linux中的计划任务(crontab)使用方式

《Linux中的计划任务(crontab)使用方式》:本文主要介绍Linux中的计划任务(crontab)使用方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录一、前言1、linux的起源与发展2、什么是计划任务(crontab)二、crontab基础1、cro

Linux换行符的使用方法详解

《Linux换行符的使用方法详解》本文介绍了Linux中常用的换行符LF及其在文件中的表示,展示了如何使用sed命令替换换行符,并列举了与换行符处理相关的Linux命令,通过代码讲解的非常详细,需要的... 目录简介检测文件中的换行符使用 cat -A 查看换行符使用 od -c 检查字符换行符格式转换将

Python FastAPI+Celery+RabbitMQ实现分布式图片水印处理系统

《PythonFastAPI+Celery+RabbitMQ实现分布式图片水印处理系统》这篇文章主要为大家详细介绍了PythonFastAPI如何结合Celery以及RabbitMQ实现简单的分布式... 实现思路FastAPI 服务器Celery 任务队列RabbitMQ 作为消息代理定时任务处理完整

Linux系统配置NAT网络模式的详细步骤(附图文)

《Linux系统配置NAT网络模式的详细步骤(附图文)》本文详细指导如何在VMware环境下配置NAT网络模式,包括设置主机和虚拟机的IP地址、网关,以及针对Linux和Windows系统的具体步骤,... 目录一、配置NAT网络模式二、设置虚拟机交换机网关2.1 打开虚拟机2.2 管理员授权2.3 设置子

揭秘Python Socket网络编程的7种硬核用法

《揭秘PythonSocket网络编程的7种硬核用法》Socket不仅能做聊天室,还能干一大堆硬核操作,这篇文章就带大家看看Python网络编程的7种超实用玩法,感兴趣的小伙伴可以跟随小编一起... 目录1.端口扫描器:探测开放端口2.简易 HTTP 服务器:10 秒搭个网页3.局域网游戏:多人联机对战4.

Linux系统中卸载与安装JDK的详细教程

《Linux系统中卸载与安装JDK的详细教程》本文详细介绍了如何在Linux系统中通过Xshell和Xftp工具连接与传输文件,然后进行JDK的安装与卸载,安装步骤包括连接Linux、传输JDK安装包... 目录1、卸载1.1 linux删除自带的JDK1.2 Linux上卸载自己安装的JDK2、安装2.1