【Hello Linux】进程概念

news2024/9/23 5:30:01

作者:@小萌新
专栏:@Linux
作者简介:大二学生 希望能和大家一起进步!
本篇博客简介:简单介绍下进程的概念

进程

  • 基本概念
  • PCB 程序控制块
    • task_struct是什么
    • task_struct里面有什么
  • 查看进程
    • 通过系统目录查看进程
    • 通过ps指令查看
  • 获取程序的pid和ppid
  • 通过fork函数创建进程
    • 如何理解fork创建的子进程
    • 如何让父子进程做不同的事
  • 进程的状态
    • 运行状态 R (run)
    • 浅度睡眠状态 S (sleep)
    • 深度睡眠状态 D (disk sleep)
    • 暂停状态-T (stop)
    • 僵尸状态 Z(zombie)
    • 死亡状态 X (dead)
  • 僵尸进程
    • 僵尸进程的危害
  • 孤儿进程

基本概念

在操作系统的书本上一般这样子解释一个进程

进程(Process):是操作系统进行资源分配的最小单位。一个进程是一个程序的一次执行过程。

可是这到底是什么意思呢?

进程和程序又有什么区别呢?

下面我们先用一张图来解释进程和程序的区别

在这里插入图片描述
我们可以看到程序首先以文件的形式保存在磁盘当中 我们双击之后加载到了内存中 由cpu加载开始运行

这个进程被加载到内存之后我们可以看到除了原本的代码之外还多了一堆的数据

还记得我们之前的说操作系统是怎么管理的嘛? 先描述 再组织

这一堆多出来的数据就是操作系统对于进程的描述 而我们将这一堆数据称为PCB(Process Control Block) 程序控制块

那么到这里就可以回答上面的问题的

进程等于程序加上PCB

PCB 程序控制块

我们上面讲过 PCB是操作系统对于进程的描述

当我们使用ps指令的时候 我们可以看到系统中存在着大量的进程
在这里插入图片描述
同样的 每个进程都对应着一个PCB

我们可以这样理解
在这里插入图片描述
每个PCB对应着一个进程的数据 它们之间使用双链表组织起来 我们可以通过PCB来找到并管理每个进程

这样子我们就把操作系统对于进程的管理转化为了对于双链表的增删查改

task_struct是什么

进程控制块(PCB)的作用是描述进程的 而Linux系统是使用c语言写出来的

我们在c语言中一般是使用一个结构体去描述一个对象 这个在linux描述进程的结构体我们就把它叫做 task_struct

task_struct和PCB的关系就像是你和程序员 task_struct是PCB

task_struct一般会被储存在内存中

task_struct里面有什么

task_struct里面包含以下信息

  • 标示符: 描述本进程的唯一标示符 用来区别其他进程

我们可以将它理解为学号

  • 状态: 任务状态 退出代码 退出信号等

我们可以将这个理解为 正常上学 休学中等等

  • 优先级: 相对于其他进程的优先级
  • 程序计数器(pc): 程序中即将被执行的下一条指令的地址
  • 内存指针: 包括程序代码和进程相关数据的指针 还有和其他进程共享的内存块的指针
  • 上下文数据: 进程执行时处理器的寄存器中的数据

上下文数据的概念十分重要 下面我会使用一个小故事来帮助理解
假设你们现在学校有几个征兵名额 你被选上了 可以去当一年的兵然后回来继续学业 那你能直接过去然后一年后直接回来嘛? 显然是不可以的 如果这样子做你会发现一年后你被勒令退学了 为什么呢? 因为你事先没有给学校打招呼啊 学校以为你旷课旷了一整年 所以说你需要先向学校报备下情况之后才能去服役 这样子回来才能够继续学业 这就是上下文信息

  • I/O状态信息: 包括显示的I/O请求 分配给进程的I/O设备和被进程使用的文件列表
  • 记账信息: 可能包括处理器时间总和 使用的时钟总和 时间限制 记账号等

因为cpu执行进程的时候要保证尽量的公平 一个进程执行了很久了 那么就需要提高另外一个进程的优先级 那么执行多久这个信息保存在哪里呢?就是在 task_struct 中的记账信息中

  • 其他信息

查看进程

我们可以通过两种方式来查看进程

  • 通过系统目录查看
  • 通过ps指令查看

通过系统目录查看进程

我们在根目录下可以找到一个叫做proc的目录
在这里插入图片描述
这个目录中含有大量的进程信息
在这里插入图片描述
我们可以发现 这些文件中有些是用数字表示的

而这些数字实际上就是程序的pid

如果我们想要查看这些进程的信息只需要进入里面就好了

在这里插入图片描述

通过ps指令查看

我们可以通过ps指令去查看进程
在这里插入图片描述
但是我们一般查看进程的时候使用的是这样子的语句

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

这段命令分为两部分

&& 连接的两个命令 如果前面执行成功了就会执行后面的语句

ps axj | head -1

这段命令的意思打出 ps axj的第一行

 ps axj | grep 66

这段命令的意思是打出所有包含66的进程
在这里插入图片描述

获取程序的pid和ppid

  • pid : pid是程序的标识符
  • ppid: ppid是当前进程的父进程的标识符

我们可以写出一段代码来实验下

其中getpid() 的程序存放在 unistd.h 头文件里面

在这里插入图片描述
之后我们写好这段代码的makefile文件

在这里插入图片描述
之后使用make命令生成可执行程序
在这里插入图片描述
运行之后我们就可以发现该进程在循环打印子进程和父进程的pid

在这里插入图片描述

通过fork函数创建进程

fork是一个系统调用级别的函数 其功能就是创建一个子进程

我们可以通过如下的代码来验证它

在这里插入图片描述
我们的代码中只写了一行打印子进程和父进程的代码

make之后看看执行结果

在这里插入图片描述
我们可以发现明明只有一行代码 而这个代码却执行了两次

并且如果仔细观察我们还能发现这样子的规律

在这里插入图片描述

一个进程的pid是另外一个进程的ppid 这就是fork的作用

如何理解fork创建的子进程

  1. 从创建层面 不论是使用指令 跑代码还是使用fork创建进程 在操作系统眼中都没有区别
  2. 从继承层面 fork出来的子进程它本身没有代码和数据 所以说它是拷贝的父进程的代码和数据

那么代码和数据是全部拷贝过来吗?

对于代码来说 是的 但是一般创建进程之前的代码是用不到的 因为已经运行到创建进程结束了

对于数据来说父子进程的数据也就是PCB大部分是共享的 但是我们也要考虑修改的情况

因为进程相对来说具有独立性 比如说我们想让父进程返回一个10 子进程返回一个20 如果说他们完全共享一个PCB是无法做到的

这里就要用到一个写时拷贝的技术

在这里插入图片描述

如何让父子进程做不同的事

父子进程是共享同一段代码的 也就是说他们能做的事情是相同的

但是如果它们只能做相同的事情我们只需要使用循环语句就好了 根本没有必要大费周章来书写一个子进程

事实上我们可以通过一个叫做pid的返回值来区分父子进程 从而达到同时进行两个任务的目的

fork函数的返回值:

我们上面说过了fork是一个函数 既然是函数那么他就有返回值

而fork的返回值是这样子的

  1. 如果子进程创建失败返回-1
  2. 如果子进程创建成功 在父进程中返回子进程的pid 在子进程中返回0

那么我们就可以利用这个返回值让父子进程做不同的事情

在这里插入图片描述
我们可以发现这是个if else语句

执行之后我们可以发现如下的结果

在这里插入图片描述

我们发现竟然if else两个语句都执行了

这就是两个进程同时运行的结果

在做业务的时候我们可以将里面的代码换成业务逻辑就可以了

进程的状态

在进程从创建到消亡的这段时间会存在不同的状态 这些状态值储存在PCB当中 操作系统会根据PCB中的状态值来决定这个进程是否该运行了是否该结束了

一般来说 常见的进程状态有以下几点

在这里插入图片描述
在我们的linux源码中对于状态有着如下的定义

/*
* 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 *task_state_array[] = {
	"R (running)",       /*  0*/
    "S (sleeping)",      /*  1*/
    "D (disk sleep)",    /*  2*/
    "T (stopped)",       /*  4*/
    "T (tracing stop)",  /*  8*/
    "Z (zombie)",        /* 16*/
    "X (dead)"           /* 32*/
};

我们可以通过ps axj来查看进程的状态

在这里插入图片描述

运行状态 R (run)

一个进程处于运行状态(running) 并不意味着进程一定处于运行当中,运行状态表明一个进程要么在运行中 要么在运行队列里 也就是说 可以同时存在多个R状态的进程

在这里插入图片描述

浅度睡眠状态 S (sleep)

一个进程处于浅度睡眠状态(sleeping) 意味着该进程正在等待某件事情的完成 处于浅度睡眠状态的进程随时可以被唤醒 也可以被杀掉

我们可以写出下面你的一段代码来验证

在这里插入图片描述
我们运行完之后让这个进程休眠30秒

在这里插入图片描述
我们可以发现该进程确实是在睡眠中的

此时我们可以使用ctrl + c 或者 kill -9 + pid 杀掉它

深度睡眠状态 D (disk sleep)

一个进程处于深度睡眠状态(disk sleep)表示该进程不会被杀掉 即便是操作系统也不行,= 只有该进程自动唤醒才可以恢复 该状态有时候也叫不可中断睡眠状态(uninterruptible sleep) 处于这个状态的进程通常会等待IO的结束

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

暂停状态-T (stop)

在Linux当中 我们可以通过发送SIGSTOP信号使进程进入暂停状态(stopped) 发送SIGSTOP信号可以让处于暂停状态的进程继续运行

还是用我们上面的代码举例

在这里插入图片描述
我们可以看到在外面发送了暂停信号了之后进程就进入了暂定状态

我们再对该进程发送SIGCONT信号 该进程就继续运行了

僵尸状态 Z(zombie)

当一个进程将要退出的时候 在系统层面 该进程曾经申请的资源并不是立即被释放 而是要暂时存储一段时间 以供操作系统或是其父进程进行读取 如果退出信息一直未被读取 则相关数据是不会被释放掉的 一个进程若是正在等待其退出信息被读取 那么我们称该进程处于僵尸状态(zombie)

僵尸状态的存在是必要的

因为如果该进程的申请的资源在其运行结束之后立即释放那么我们便不知道该进程完成的如何

要知道它完成的如何我们必须要它的调用者来接受它的返回值 在了解完毕之后才可以让这个进程终止

我们在写c语言代码的时候通常在最后加上一个返回值

int main()
{
   // ..
   return 0;
}

这个return的值实际上是返回给操作系统的

我们可以使用 echo $? 命令来查询上次命令的返回值
在这里插入图片描述

死亡状态 X (dead)

我们一般不能查询到进程的死亡状态 因为在进程死亡的那一瞬间该进程的所有资源将会被释放 该进程也不存在了 所以说我们看不到它

僵尸进程

处于僵尸状态的进程就叫做僵尸进程

我们可以人为的制造一个僵尸进程 具体操作就是让父进程一直运行 然后子进程退出 这样子的话子进程就一直无法将返回值传递给父进程 那么它就会一直处于僵尸状态

我们写出这样子的代码
在这里插入图片描述

之后查询子进程的pid

在这里插入图片描述
我们可以看到他的状态就变成了Z 僵尸状态

僵尸进程的危害

  1. 僵尸进程的退出状态必须一直维持下去 因为它要告诉其父进程相应的退出信息 可是父进程一直不读取 那么子进程也就一直处于僵尸状态
  2. 僵尸进程的退出信息被保存在task_struct(PCB)中 僵尸状态一直不退出 那么PCB就一直需要进行维护
  3. 若是一个父进程创建了很多子进程 但都不进行回收 那么就会造成资源浪费 因为数据结构对象本身就要占用内存
  4. 僵尸进程申请的资源无法进行回收 那么僵尸进程越多 实际可用的资源就越少 也就是说 僵尸进程会导致内存泄漏

孤儿进程

在Linux中的进程大多是父子关系 万一一个进程的子进程还没有结束但是他的父进程结束了 那么我们就称这个进程为孤儿进程

如果没有父进程来管理这个子进程那么他就会一直占用资源 所以说为了防止这种情况 我们设计了让1号init进程来领养这个进程

我们可以写出下面的代码来实验

在这里插入图片描述
我们之后可以发现
在这里插入图片描述
在这里插入图片描述
子进程的父进程变为了 1 (init进程)

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

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

相关文章

22.2.26打卡 Codeforces Round #853 (Div. 2)

A题极端考虑, 只要存在一个前缀数组的最大公约数小于等于2, 将其放在数组最前端, 那么保证能够满足题目要求数据范围这么小, 果断暴力Serval and Mochas Array题目描述Mocha likes arrays, and Serval gave her an array consisting of positive integers as a gift.Mocha thin…

ARM Context synchronization event和Instruction Synchronization Barrier

在Arm architecture里,经常提到Context synchronization event(CSE)和Explicit synchronization,Context synchronization events在之前是叫作context synchronization operations。Explicit synchronization是Context synchronization event的结果&…

C++9:优先级队列以及仿函数和反向迭代器

目录 优先级队列的基本增删查改实现 仿函数 反向迭代器 优先级队列的本质其实是一个堆,具体到底层的数据结构其实是有数学关系所形成的一个类似二叉树的结构 至于其优先级的这个特性,跟大堆小堆的性质是相同的,只不过它使用了仿函数来控制…

bool与引用类型

bool与引用类型bool类型介绍与使用bool(布尔类型)大小&#xff1a;1个字节返回值有两个&#xff1a;1(true)&#xff0c;0(false)#include<iostream>using namespace std;int main() {bool a false;bool b true;cout << "a " << a << end…

Lighthouse组合Puppeteer检测页面

如上一篇文章lighthouse的介绍和基本使用方法结尾提到的一样&#xff0c;我们在实际使用Lighthouse检测页面性能时&#xff0c;通常需要一定的业务前置条件&#xff0c;比如最常见的登录操作、如果没有登录态就没有办法访问其他页面。再比如有一些页面是需要进行一系列的操作&a…

从编年史角度看大数据兴起

开源大数据编年史大数据发展的各阶段大数据诞生初期大数据百花齐放的发展之路追求性能的大数据成熟期大数据发展的各阶段 开源大数据的编年史的话&#xff0c;实际上分为三个阶段。一般来说它分为初期、发展期、成熟期。 初期就是大数据刚开始萌芽的一个阶段&#xff0c;它从…

java 8 中的实用技巧

1 判断2个对象是否相等Objects.equals(a, b)(1) 比较时&#xff0c; 若a 和 b 都是null, 则返回 true, 如果a 和 b 其中一个是null, 另一个不是null, 则返回false。注意&#xff1a;不会抛出空指针异常。(2) a 和 b 如果都是空值字符串&#xff1a;"", 则 a.equals(b…

深入浅出解析ChatGPT引领的科技浪潮【AI行研商业价值分析】

Rocky Ding写在前面 【AI行研&商业价值分析】栏目专注于分享AI行业中最新热点/风口的思考与判断。也欢迎大家提出宝贵的意见或优化ideas&#xff0c;一起交流学习&#x1f4aa; 大家好&#xff0c;我是Rocky。 2022年底&#xff0c;ChatGPT横空出世&#xff0c;火爆全网&a…

CXL互联标准简介及相关资料

毕设是实现CXL的type3扩展内存设备&#xff0c;因为CXL技术非常新&#xff0c;2019年推出&#xff0c;本专栏也是记录CXL的相关知识与一些浅薄的理解 文章目录CXL出现的背景CXL是什么其他互联总线介绍CXL胜出的原因CXL内容简介包含三种协议 CXL.io/cache/memory支持三种设备类型…

SQL注入原理及漏洞利用(入门级)

文章目录一、什么是SQL注入漏洞&#xff1f;二、 SQL查询语句三、SQL注入分类数字型&#xff08;整型&#xff09;注入字符型注入搜索型注入四、SQL注入漏洞形成原因一、什么是SQL注入漏洞&#xff1f; 攻击者利用Web应用程序对用户输入验证上的疏忽&#xff0c;在输入的数据中…

基于Istio的高级流量管理二(Envoy流量劫持、Istio架构、高级流量管理)

文章目录一、Envoy流量劫持机制&#xff08;Iptables规则流转&#xff09;1、流量出向劫持流程&#xff08;1&#xff09;envoy怎样劫持入向流量&#xff1f;&#xff08;2&#xff09;Envoy劫持到流量之后&#xff0c;干什么&#xff1f;&#xff08;查询目的地&#xff09;&a…

tess4j简单使用入门

tess4j下载 下载地址: https://sourceforge.net/projects/tess4j/ 不要直接下载,点击files,然后下载最新版 下载解压后放到指定的目录即可,这里放到d:\jar目录下 tess4j根目录: d:\jar\tess4j tess4j使用 把test4j项目目录中dist和lib目录下的所有jar包导入到需要的项目中…

【云原生】k8s 离线部署讲解和实战操作

文章目录一、概述二、前期准备1&#xff09;节点信息2&#xff09;修改主机名和配置hosts3&#xff09;配置ssh互信4&#xff09;时间同步5&#xff09;关闭防火墙6&#xff09;关闭 swap7&#xff09;禁用SELinux8&#xff09;允许 iptables 检查桥接流量三、开始部署1&#x…

【OC】块初识

Block简介 Blocks是C语言的扩充功能。可以用一句话来表示Blocks的扩充功能&#xff1a;带有自动变量的匿名函数。 匿名函数 所谓匿名函数就是不带有名称的函数。C语言的标准不允许存在这样的函数。例&#xff1a; int func(int count);它声明了名称为func的函数。下面的源代…

STM32 ROS控制器底层代码讲解

本文主要对控制器底层代码的整天架构进行讲解。控制器由两部分组成一部分是BootLoader,另一部分是APP&#xff1b;BootLoader主要用于固件升级&#xff0c;APP则作为应用程序。BootLoader的地址为:0x8000000~0x8008000App的地址为:0x8010000~0x8FFFFFF参数保存地址为&#xff1…

基本密码技术

AESAES取代DES&#xff0c;是一种对称加密技术&#xff0c;分为AES-128/192/256, 其分组长度固定为128b&#xff0c;若最后一个分组长度不够&#xff0c;需要补全至128b长度。所支持的秘钥长度分别为128b/192b/256b.分组密码模式AES是对明文进行分组之后逐块进行加密&#xff0…

2023年软考高级网络规划设计师

网络规划设计师是软考高级考试科目之一&#xff0c;也是比较难的科目&#xff0c;据官方数据统计网规每年的通过率很低&#xff0c;而且每年只有下半年11月份考一次&#xff0c;如果是直接裸考&#xff0c;估计很悬哦~ 但是你参加考试获得证书的过程就是一个学习网络规划系统知…

【python学习笔记】:SQL常用脚本(一)

1、行转列的用法PIVOT CREATE table test (id int,name nvarchar(20),quarter int,number int) insert into test values(1,N苹果,1,1000) insert into test values(1,N苹果,2,2000) insert into test values(1,N苹果,3,4000) insert into test values(1,N苹果,4,5000) insert…

本周大新闻|索尼PS VR2立项近7年;传腾讯将引进Quest 2

本周大新闻&#xff0c;AR方面&#xff0c;传立讯精密开发苹果初代AR头显&#xff0c;第二代低成本版将交给富士康&#xff1b;iOS 16.4代码曝光新的“计算设备”&#xff1b;EM3推出AR眼镜Stellar Pro&#xff1b;努比亚将在MWC2023推首款AR眼镜。VR方面&#xff0c;传闻腾讯引…

编辑器、论坛、评论列表图文混排的一些思路

好久没写帖子了&#xff0c;今天写一个吧 众所众知从用户那里拿到的数据直接innerHtml插入 有被xss攻击的风险&#xff0c;所以一般会转义,拿csdn编辑文章的来举个例子 通过前端转义 ‘>’后,传给后台&#xff1b;这里title没有用innerHtml而是文本所以不需要转义。 前端请…