linux——进程(1)

目录

一、概念

1.1、认识进程

1.2、进程描述符(PCB)

1.3、进程的结构体(task_struct)

二、查看进程

三、获取进程的Pid和PPid

3.1、通过系统调用获取进程的PID和PPID

四、创建进程

4.1、fork()

4.2、用if进行分流

五、进程状态

5.1、操作系统进程状态

5.2、Linux进程状态

六、僵尸进程

6.1、僵尸状态

6.2、僵尸进程的危害

七、孤儿进程


一、概念

1.1、认识进程

课本概念:程序的一个执行实例,正在执行的程序等。
内核观点:担当分配系统资源(CPU时间,内存)的实体。

 进程是操作系统中用于描述程序执行过程的动态概念,是资源分配和调度的基本单位,具有多个基本特征和状态。

我们知道,代码被编译链接后会形成一个可执行程序。当我们在电脑上双击软件的图标或者在手机上打开App,实际上就是在运行它们的可执行程序。

而这个可执行程序本质上是一个文件,是放在磁盘上的。当我们双击这个可执行程序将其运行起来时,本质上是将这个程序加载到内存当中了,因为只有加载到内存后,CPU才能对其进行内容的读取执行。而一旦将这个程序加载到内存后,我们就不应该将这个程序再叫做程序了,而是应该将其称之为进程。

 在Linux下,运行一条命令,./xxx运行可执行程序时,其实就是在系统层面上创建了一个进程。

1.2、进程描述符(PCB)

进程信息被放在一个叫做进程控制块的数据结构中,可以理解为进程属性的集合。
PCB(process control block),Linux操作系统下的PCB是: task_struct

系统当中可以同时存在大量进程,而当你开机的时候启动的第一个程序就是我们的操作系统(即操作系统是第一个加载到内存的),我们都知道操作系统是做管理工作的,而其中就包括了进程管理。那么操作系统是怎么对进程进行管理的呢?

其实就是我们在操作系统中所讲到的:先描述,再组织。当一个进程出现时,操作系统就立马通过创建一个 struct/class 来对其进行描述,之后对该进程的管理实际上就是对其描述信息的管理。

操作系统将每一个进程都会对其进行描述,所以会形成多个PCB,并将这些PCB以双向链表的形式组织起来,之后对进程的管理就是对这个双向链表的增删查改。例如:退出一个进程实际上就是先将该进程的PCB从该双链表当中删除,然后操作系统再将内存当中属于该进程的代码和数据进行释放或是置为无效。

所以,严格来说,进程 = 对应的代码和数据 + 进程对应的PCB结构体

1.3、进程的结构体(task_struct)

1、在Linux中描述进程的结构体叫做task_struct。
2、task_struct是Linux内核的一种数据结构,它会被装载到RAM(内存)里并且包含着进程的信息。

注:PCB和task_struct的关系:PCB是task_struct这一类描述进程的结构体的统称。只是在Linux中PCB是task_struct。

task_struct中的内容:

标示符:描述本进程的唯一标示符,用来区别其他进程。
状态:任务状态,退出代码,退出信号等。
优先级:相对于其他进程的优先级。
程序计数器:程序中即将被执行的下一条指令的地址。
内存指针:包括程序代码和进程相关数据的指针,还有和其他进程共享的内存块的指针。

上下文数据:进程执行时处理器的寄存器中的数据[休学例子,要加图CPU,寄存器]。
I/O状态信息:包括显示的I/O请求,分配给进程的I/O设备和被进程使用的文件列表。
记账信息:可能包括处理器时间总和,使用的时钟数总和,时间限制,记账号等。
其他信息:......

二、查看进程

在根目录下有一个名为proc的系统文件夹。文件夹当中包含大量进程信息,这些数字其实是某一进程的PID,对应文件夹当中记录着对应进程的各种信息。我们若想查看PID为1的进程的进程信息,则查看名字为1的文件夹即可。

我们还可以通过ps命令来查看进程:

 单独使用ps 会显示所有进程的信息。ps axj

ps命令与grep命令搭配使用,即可只显示某一进程的信息。

ps axj | head -1 && ps axj | grep proc

三、获取进程的Pid和PPid

3.1、通过系统调用获取进程的PID和PPID

通过使用系统调用函数,getpid和getppid(获取当前进程的父进程ID)即可分别获取进程的PID和PPID。如下图:

下面我们通过ps来查看一下进程的id是否与打印得到的id相同。是相同的

四、创建进程

4.1、fork()

fork是一个系统调用函数,其功能就是创建一个子进程。返回值:失败时,-1;成功时,a. 给父进程返回子进程的pid,b. 给子进程返回0(fork可以有两个返回值)。

比如我们先编写一个下面的代码:

运行结果:

这个结果就和我们以前所学的知识相冲突了,为什么会有两个ret值呢?一个变量不是应该只有一个值的吗?而出现这种现象就和进程有关系了。

紧接着,我们就来看一看它们的进程:

fork之后,代码是父子共享的,数据各自开辟空间,私有一份。所以子进程和父进程都可以执行printf,进而打印出不同的ret。 

但是,我把一个子进程创建出来是为了让它去执行和父进程一样的代码吗?肯定不是的,这样做没有任何意义。我们新创建一个进程肯定是要让它去执行不同的代码,将任务拆解成小任务,让不同的进程去执行不同的任务,这样才能够提高效率。

4.2、用if进行分流

所以为了让不同的进程去执行不同的任务,在 fork 之后通常要用 if 进行分流。根据父进程和子进程获取到fork函数的返回值不同,我们就可以来让父子进程执行不同的代码,从而做不同的事。如下面的代码:

fork创建出子进程后,子进程会进入到 else if 语句的循环打印当中,而父进程会进入到 else 语句的循环打印当中。 如下图:

五、进程状态

5.1、操作系统进程状态

1、新建
字面意思,就是新建立的进程。

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

运行状态:进程PCB在运行队列里排队就是运行状态(在等待CPU资源)。注:不是说这个进程正在运行,才是运行状态。即进程可能正在运行,也可能在运行队列中。

3、阻塞
系统中存在各种资源,如磁盘、网卡显卡等,在使用这些资源时,它们也有自己的队列。故系统中不止存在一种队列。CPU的队列就叫运行队列。

等待非CPU资源就绪时,就是阻塞状态。(即不在运行队列中,在其他资源的队列中)。

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

5.2、Linux进程状态

下面是进程状态在Linux内核中的定义:

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)

 注:状态后面带+,意味着这个任务是前台进程。前台进程:一旦进程运行起来,你的命令行解释器就不能使用,只有通过 CTRL C 使进程停下来才能使用。

后台进程:在运行时,加上&,即让这个进程在后台运行。会返回进程的PID。且 CTRL C也不能使它停下来。

使它停下来的方法:kill -9 PID

S睡眠状态(sleeping)  

意味着进程在等待非CPU资源就绪(这里的睡眠也叫做可中断睡眠(interruptible sleep))。相当于阻塞状态。

S是浅度睡眠,可以被终止。能够被os杀掉。我们也可以使用kill命令将该进程杀掉。

D磁盘休眠状态(Disk sleep)

也叫不可中断睡眠状态(uninterruptible sleep),在这个状态的进程通常会等待IO的结束。D是深度睡眠,无法被OS杀掉,只能通过断电、自动唤醒才可以恢复。

例如,某一进程要求对磁盘进行写入操作,那么在磁盘进行写入期间,该进程就处于深度睡眠状态,是不会被杀掉的,因为该进程需要等待磁盘的回复(是否写入成功)以做出相应的应答。(磁盘休眠状态)。

T停止状态(stopped)

X死亡状态(dead)

死亡状态只是一个返回状态,当一个进程的退出信息被读取后,该进程所申请的资源就会立即被释放,该进程也就不存在了,所以你不会在任务列表当中看到死亡状态(dead)

六、僵尸进程

6.1、僵尸状态

是一个比较特殊的状态。当进程退出并且父进程没有读取到子进程退出的返回代码时就会产生僵死(尸)进程。

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

简单来说,就是:一个进程已经退出,但是还不允许被os释放,处于一个被检测的状态——僵尸状态。

例如,对于以下代码,fork函数创建的子进程在打印7次信息后会退出,而父进程会一直打印信息。也就是说,子进程退出了,父进程还在运行,但父进程没有读取子进程的退出信息,那么此时子进程就进入了僵尸状态。

维持该状态,为了让父进程和操作系统来回收。然后由z状态变为x状态。

6.2、僵尸进程的危害

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

七、孤儿进程

父进程如果提前退出,子进程后退出,这种情况下子进程就称之为“孤儿进程”。

孤儿进程必须被1号init进程(系统本身)领养。

为什么子进程要被领养呢?因为之后在子进程要退出时,它的父进程已经不在了,需要领养进程来进行回收。

我们以下面的代码为例:

最开始,父进程和子进程都在。

然后,父进程会退出,子进程成为孤儿进程

它的父进程的pid也变成了1,即该孤儿进程被1号进程领养了。

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

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

相关文章

【PyQt错误集 - 1】:PyQt调用多线程导致窗口异常退出的问题分析(进程已结束,退出代码 -1073741819 (0xC0000005))

文章目录 问题分析解决方法 问题分析 运行以下程序: def run_thread_WTD(self):threading.Thread(targetself.WTD).start()def WTD(self):word_path self.word_path.text()# textBrowser为多行文本框QTextEditself.pycorrectorKenlm(word_path, textBrowser)# ke…

NCV1117ST50T3G线性稳压器芯片中文资料规格书PDF数据手册引脚图图片价格参数

产品概述: NCP1117系列为低压差(LDO)正向线性电压稳压器,能够提供超过1.0A的输出电流,800mA时温度范围内最大压差为1.2V。这一系列包括八个固定输出电压:1.5V、1.8V、2.0V、2.5V、2.85V、3.3V、5.0V 和 12…

2024/3/15 记录简版抖音部署遇到的问题

1、Centos连不上网 参考这一篇:虚拟机 CentOS 有线连接图标直接消失,网络连接不上,网络连接失败的解决方案(亲测有效)_centos网络图标不见了-CSDN博客 2、SQLyog连接不到docker中的mysql 原因是对密码有加密过程 &a…

STM32F407_多点电容触摸(GT911)驱动

目录标题 前言1、简单介绍2、触摸芯片与主机的硬件连接3、内部寄存器3.1、控制寄存器(0X8040)3.2、配置寄存器组(0X8047~0X8100)3.3、状态寄存器(0x814E)3.4、坐标寄存器(0x8150-0x8177) 4、初始化流程4.1、IIC地址选择4.2、更新G…

FTP服务器的工作原理

1.1、概述 FTP服务器是网络中提供文件存储和访问服务的服务器,无论是个人还是企业,都可以搭建FTP服务器,用来上传数据、下载数据和共享文件。FTP采用C/S(客户端/服务器)架构,用户只要通过FTP客户端程序连接…

html--简历

文章目录 html html <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><meta name"viewport" content"maximum-scale1.0,minimum-scale1.0,user-scalable0,widthdevice-width,initial-scale1.0&qu…

字母异位词分组【每日一题】

可以通过案例找到规律&#xff0c;每个词排序完后是同一个&#xff0c;所以通过hasmap存储排序过的值做key&#xff0c;值是存储单词集合。 package HasTable;import java.util.*;class Solution {static List<List<String>> groupAnagrams(String[] strs) {Map&l…

jupyter notebook 突然莫名奇妙的白屏

jupyter notebook 突然莫名奇妙的白屏 事件背景&#xff1a; 最近在折腾openai&#xff0c;哎&#xff0c;一言难尽&#xff0c;使用的是conda管理python版本的切换&#xff0c;使用jupyter notebook来运行python程序&#xff0c;其实PyCharm也行&#xff0c;但是&#xff0c;…

JAVA构造方法的作用

JAVA构造方法主要有以下作用&#xff1a; 1. 初始化对象的状态&#xff1a;构造方法用于创建对象时&#xff0c;可以初始化对象的实例变量和其他属性&#xff0c;为对象的状态赋初值。 2. 调用父类构造方法&#xff1a;构造方法还可以用来调用父类的构造方法&#xff0c;通过su…

uView Code 验证码输入框

考虑到用户实际发送验证码的场景&#xff0c;可能是一个按钮&#xff0c;也可能是一段文字&#xff0c;提示语各有不同&#xff0c;所以本组件 不提供界面显示&#xff0c;只提供提示语&#xff0c;由用户将提示语嵌入到具体的场景 #平台差异说明 App&#xff08;vue&#xf…

lqb省赛日志[11/37] -[dfs]

一只小蒟蒻备考蓝桥杯的日志 文章目录 笔记刷题心得小结 笔记 最近对二维数组[][]&#xff0c;xy的区分好混乱啊。。。 刷题 P1101 单词方阵P2404 自然数的拆分问题P1596 [USACO10OCT] Lake Counting SP1162 填涂颜色 心得 莫名其妙就爆0了&#xff0c;但是样例对&#x…

【递归搜索回溯专栏】专题二:二叉树中的深搜----二叉树剪枝

本专栏内容为&#xff1a;递归&#xff0c;搜索与回溯算法专栏。 通过本专栏的深入学习&#xff0c;你可以了解并掌握算法。 &#x1f493;博主csdn个人主页&#xff1a;小小unicorn ⏩专栏分类&#xff1a;递归搜索回溯专栏 &#x1f69a;代码仓库&#xff1a;小小unicorn的代…

git |常用命令

git 命令 非常常用 主流的仓库管理服务器&#xff0c;svn 和git 接下来&#xff0c;介绍git 操作&#xff08;自用 先讲一个简单的demo 流程 环境&#xff1a;centos、git #先创建一个本地 git 文件夹 mkdir test && cd ./test #写一个README.md #echo “# 张不大 的de…

MySQL调优:explain详解

MySQL的EXPLAIN命令用于获取SQL查询的执行计划&#xff08;Execution Plan&#xff09;&#xff0c;它揭示了MySQL服务器如何执行给定的SELECT语句&#xff0c;包括如何连接表、使用索引以及MySQL优化器选择的查询路径等重要信息。这对于分析查询性能、找出潜在的瓶颈并优化SQL…

redis发布订阅与stream类型

发布订阅 redis发布订阅(pub/sub)是一种消息通信模式&#xff1b;发送者(pub)发送消息&#xff0c;订阅者(sub)接收消息。redis客户端可以订阅任意数量的频道。 基础命令&#xff1a; 语法 redis publish命令基本语法如下&#xff1a; redis 127.0.0.1:6379> PUBLISH ch…

Matlab|考虑可再生能源消纳的电热综合能源系统日前经济调度模型

目录 1 主要内容 模型示意图 目标函数 程序亮点 2 部分程序 3 程序结果 4 下载链接 1 主要内容 本程序参考文献《考虑可再生能源消纳的建筑综合能源系统日前经济调度模型》模型&#xff0c;建立了电热综合能源系统优化调度模型&#xff0c;包括燃气轮机、燃气锅炉、余热…

Arduino RP2040 + SSD1306 I2C OLED +LittleFS存储GBK字库实现中文显示

Arduino RP2040 + SSD1306 I2C OLED +LittleFS存储GBK字库实现中文显示 📌LittleFS插件安装,可以参考《Arduino RP2040 LittleFS的使用介绍》🎈相关内容《Arduino esp8266 软件I2C SSD1306 +LittleFS存储GBK字库实现中文显示》🔖基于Earle F. Philhower, III的核心固件开…

如何针对机械表进行识别读数

识别机械表的读数通常涉及到图像处理和模式识别技术。以下是一个简单的例子&#xff0c;使用Python和OpenCV库来识别机械表的读数。这个例子假设表盘是静止的&#xff0c;并且有一个清晰的背景。 首先&#xff0c;你需要安装OpenCV库&#xff08;如果你还没有安装的话&#xff…

Python基础(七)之数值类型集合

Python基础&#xff08;七&#xff09;之数值类型集合 1、简介 集合&#xff0c;英文set。 集合&#xff08;set&#xff09;是由一个或多个元素组成&#xff0c;是一个无序且不可重复的序列。 集合&#xff08;set&#xff09;只存储不可变的数据类型&#xff0c;如Number、…

修改yolov9的模型打印不出来Gflops的解决办法

正在修改yolov9的模块&#xff0c;发现修改后的模型没有GFlops这个参数 解决办法&#xff1a; 找到utils/torch_utils.py这个文件&#xff0c;有一个model_info函数 然后将其中的stride改为固定的640就可以打印了。 stride max(int(model.stride.max()), 32) if hasattr(mo…