【Linux】初见,进程概念

前言:

        上文我们讲到了Linux下的第一个程序:进度条       【Linux】LInux下第一个程序:进度条-CSDN博客

        本文我们来讲一讲Linux中下一个非常重要的东西:进程

1.冯诺依曼体系结构

我们所见的大部分计算机都是遵循的冯诺依曼体系结构

我们的计算机都是由一个个硬件所组成的

  • 输出设备:显示器、音响、摄像头、网卡.......
  • 输入设备:鼠标、键盘 、网卡.......
  • 中央处理器(CPU):包含运算器、控制其等等等等......

对于冯诺依曼体系结构我们要注意以下几点:

  • 存储器:其实就是我们所说的内存。相应的外存就是我们说所的磁盘
  • 输入与输出(Input/Output,IO):输入与输出我们要站在内存的角度来看待,外设的数据流出内存叫做输入,内存将数据交给输入设备叫做输出。
  • CPU与内存:CPU在数据层面上只能直接访问内存,并不能直接访问硬件设备。所以一切软件的运行都想要先将其加载到内存才行。加载的本质其实是Input,数据从一个设备“拷贝”到另一个设备。拷贝的效率决定了体系结构的效率
  • 软件运行:软件的运行是通过CPU执行我们的代码,访问我们的数据来得以实现的。
  • 理解内存:假设没有内存,CPU直接从输入设备中拿去数据,再交由输出设备。我们知道输入设备与输出设备的速度是远远的慢与CPU的。这就导致了不论CPU有多快都没用,CPU始终要等着输入设备的数据过来才能开始处理,这个设备的效率全部取决于了外设。这显然是不合理的。

        而内存的出现解决了,CPU与外设之间运算速度不匹配的弊端。内存会提前将输入设备中的数据拿过来,尽可能的减少CPU与外设之间的速度差。

  • 理解数据的流动

2.操作系统(Operator System)

2.1基本概念

任何一个计算机都包含一个最基本的程序:OS(操作系统)

操作系统本质是一款用于管理软硬件的软件

广义的操作系统包含:内核(进程管理、文件管理、内存管理、驱动管理)

                                    其他程序(外壳shell、函数库等等等等)

狭义的操作系统包含:内核

2.2设计OS的目的是什么

对下:与硬件交互,管理软件与硬件的资源(手段)

对上:为应用程序提供一个良好的运行环境(目的)

注意:

1.操作系统是封装起来的任何人都无法访问其内部,只能通过操作系统给用户提供的接口(既系统调用)来执行功能

2.计算机上的任何操作都必须访问操作系统,且只能通过调用系统接口实现。其接口本质就是函数,只不过是系统提供的。

3.软硬件结构都为层状结构

4.我们的程序只要是访问了硬件(比如显示器,磁盘)那它就必定会贯穿整个软硬件体系结构

5.我们常用的库函数:printf,显示器上打印信息。它也访问了硬件设置,这也就意味着这个库函数底层封装了系统调用

2.3理解操作系统的“管理”

        在学校的管理体系中,校长是管理层,辅导员是执行层,而学生则是被管理者。校长拥有决策权,而执行校长的决定不可能由校长亲自执行,而是辅导员来。

        在计算机体系中,校长就相当于是操作系统。辅导员相当于是驱动程序。学生则相当于是底层硬件

“校长”应该如何管理?

        校长要管理学生,但是校长不可能将想要管理的学生一个个都喊到办公室来。校长与学生不必见面。更合理的做法是校长通过学生册里面的信息来进行管理,做出的决定交由辅导员来执行。

1.管理者与被管理者不必见面

2.管理者如何进行管理?通过数据进行管理

3.既然不见面,那数据从何而来?通过中间层“辅导员”--->驱动程序获得

“校长”管理方式进化之路

管理方式1.0:

通过表格来管理学生

管理方式2.0:

校长觉得表格管理太不方便了,于是想使用计算机来管理信息

先通过结构体来“描述”学生的信息,创建一个又一个对象来保存信息。

保存了众多学生数据,又如何管理这些数据呢?答案是通过数据结构来管理

以上这种管理方式被我们称作:先描述再组织

那么操作系统是如何管理驱动程序、进程或者其他东西呢?答案也是先描述:使用类先表示属性,再组织:使用恰当的数据结构来进行管理。

2.4理解系统调用

1.操作系统要对上提供服务

2.操作系统不相信任何人

        操作系统是为了我们更好的使用计算机。但操作系统是封装起来的,任何人都不能访问其内部,想要使用操作系统只能通过操作系统提供的“系统调用”。

        操作系统就像银行,你要存钱或者取钱都只能在银行提供的ATM机或者窗口上办理,银行不可能让你自己进到银行金库里取钱或者存钱。

        不论是Linux、windows还是macOS这些常见的操作系统都是用C语言写的,所以“系统调用”的本质其实是C函数,只不过是由操作系统提供。通过调用系统提供的C函数让操作系统执行我们想要的操作

        仅仅有“系统调用”对于不太了解操作系统的人来说上手还是太困难了。所以为了我们普通人更好的使用操作系统,就有了我们所说的:库、shell外壳、指令等等。这些都是在底层封装了“系统调用”以便于我们更好的使用。这二者是上下层的关系

3.进程

3.1什么是进程?

我就不念叨书上晦涩难懂的定义了,看不懂也没啥用。直接上图!

        上面我们说到了操作系统的管理方式是:先描述再组织。同样的操作系统管理进程也是先使用结构体“描述”其中包含进程的所有属性,再使用数据结构“组织”

        当我们运行我们的可执行程序时,代码和数据会加载到内存中。此时操作系统会创建一个结构体,其中包含了test.exe的所有属性。并且会有对应的指针指向对应的代码和数据。

        所谓进程其实就是:包含对应所有属性的结构体对象+代码和数据

        补充:进程的创建规则是由父进程创建子进程

PCB

操作系统创建包含所有属性的结构体有一个专业的名字叫做:进程控制块。简称为PCB(process control block)        

        Linux操作系统下的PCB是:task_struct。是位于内核的一种数据结构,它会被装在到RAM(内存)中记载进程信息。

task_struct

我们知道了task_struct是一个结构体包含了进程的所有属性,那么大概有那些类型的属性呢?

  • 标示符:描述本进程的唯一标志(pid)用于区别其他进程
  • 状态:表示任务状态,退出代码,退出信号等等
  • 优先级:相对于其他进程的优先级
  • 程序计数器:程序中即将被执行的下一条指令的地址
  • 内存指针:包含指向代码和数据的指针,以及和其他进程共享内存块的指针
  • 上下文数据:进程执行时处理器的寄存器中的数据
  • I/O状态信息:包括显示的I/O请求,分配给进程的I/O设备和被进程使用的文件列表
  • 记账信息:可能包含处理器时间总和,使用的时钟总和,时间限制,记账号等等

task_struct在linux系统中的组织方式是:双向链表

3.2初见进程

首先我们先介绍一下我们初见进程认识的第一个系统调用:getpid

        如图,getpid的功能是获得调用getpid函数的进程的标识符(简称pid)。包含在<unistd.h>库中。无需传参,返回pid_t类型的值(有同学可能比较疑惑pid_t是什么类型,其实这是由操作系统提供的类型与C语言中的int类型一致都是整型)

先编写一个简单的代码和makefile

运行成功,得到具体的pid,证明当前确实是进程 

3.3查看进程

查看进程信息可以通过指令查看,也可以通过系统文件查看

指令查看

  • 指令ps、指令top都可以查看进程信息
  • ps  ajx可以一键查看全部进程信息,但为了看我们想看的进程可以使用管道+grep进行过滤

这样就看见了我们之前执行的进程信息这里同学可能会注意到为什么grep进程也被我们查出来了,这里简单说一下:因为grep指令也是进程,执行test关键字过滤的同时gerp进程中也有test关键字,所以被一起查出来了

        我们看见了一长串的进程信息但是我们不知道这些信息分别代表什么含义。所以我们可以使用:head -1指令,让其显示进程信息的第一行内容(&& 或者 ;同时执行左右两个指令)

  • top指令也可以查看进程信息,不过top是实时更新的

文件查看

  • 进程信息可以通过 /proc 的系统文件进行查看

可以指定具体的进程查看其详细内容 

 补充:

在上图我们看见就两个高亮的字符:cwd和exe,并且后面都跟了一个地址。

cwd:表示当前工作路径(current work dir)。进程在启动时会记录下自己当前所在的路径

exe:进程在启动时会记录可执行程序所在的路径

系统调用:chdir可以修改进程的cwd

杀死进程

杀死进程有两种方式

  1. ctrl + c:无脑杀死当前台运行的进程
  2. kill -9  pid:杀死指定pid的进程

3.4父进程

上面我们讲到了getpid,不知道大家有没有注意到在这个图里面还有一个函数叫做getppid

        getpid是获取当前进程的pid,而getppid这是获取当前这个进程的父进程的pid

        注:linux中进程的创建都是由父进程完成的

        我们可以通过代码来看看ppid

        通过不断的执行杀死再次执行,我们可以发现,子进程的pid是不断变换的,而父进程的pid则是一直不变的。我们可以通过查询父进程的pid来看看父进程到底是什么东西

        查询之后我们发现父进程是一个bash

        bash其实就是我们所说的命令行解释器(补充:os会给每一个登录用户都分配一个hash,如果同时登录3个用户就会分配3个bash

        bash是命令行解释器,那其实也是一个进程,我们执行的命令也是一个进程。从这里我们就可以知道,我们输入指令执行对应的进程,都是由bash这个父进程来创建的

4.创建进程

在上面我们知道了,我们输入指令执行的进程,都是通过hash这个父进程来进行创建的。那么父进程是如何创建子进程的呢?

4.1如何创建进程

创建进程主要通过系统调用:fork来实现

先上代码,看看具体效果

#include <stdio.h>
#include <unistd.h>int main()
{printf("执行父进程:%d\n",getpid());fork();printf("执行进程:%d\n",getpid());                                                                                                                                                       
}

        我们可以看见出现两个不同的pid,这说明了子进程确实创建出来了

        但是为什么会有3个输出呢?我们接着往下看。

4.2fork相关问题

进程创建具体逻辑

        我们知道进程是由PCB+代码和数据组成的。父进程创建子进程时,会将自己的PCB数据拷贝给子进程,然后子进程在进行相应的修改所以父子进程的PCB数据大部分都是一样的)。在没有新代码加载进来时,子进程是默认与父进程共享代码和数据的(我们的代码就没有加载新数据)

        我们的代码再第一个输出后创建了子进程,而子进程是和父进程共享代码的。父进程继续向下执行第二个printf输出对应内容,子进程不会执行已经执行过的代码,只会执行还没有执行的代码。所以子进程执行第二个printf输出对应内容。也就是我们所看到了最后输出。

fork返回值

RETURN VALUE
       On success, the PID of the child process is returned in the parent, and 0 is returned in the child.  On failure, -1 is returned in the parent, no child process is  created,  and  errno is set appropriately.

        以上是关于fork返回值的文档描述。我们可以看到:如果创建成功,将会返回子进程的pid给父进程,返回0给子进程。如果创建失败则返回-1给父进程

        看到这里我们可能会很震惊,fork居然会返回两个值吗??但事实上确实是的!我们可以通过代码来验证一下。

#include <stdio.h>
#include <unistd.h>int main()
{pid_t pid = fork();if(pid<0){   printf("创建失败");}   else if(pid == 0){   //子进程printf("我是一个子进程:%d,这是我的父进程:%d\n",getpid(),getppid());}   else if(pid > 0){   printf("我是一个父进程:%d,这是我的父进程:%d\n",getpid(),getppid());}   
} 

        执行代码,我们可以看到同时输出了父进程和子进程,这就说明了fork确实是返回了两个值

        但与此同时,我们心中的疑问可能更多了

为什么fork要给父子进程各自返回不同的值?

        因为子进程是由父进程创建的,父进程可能同时拥有多个子进程,为了区分不同的子进程,父进程需要子进程的pid。

为什么fork会返回两个返回值?  

        fork函数的功能是创建子进程,执行fork函数时,当子进程创建的一系列动作完成之后,才会返回pid

        也就是说返回pid之前子进程就已经创建完成了,并且已经放入调度队列中开始执行了!上面我们讲到过子进程只会执行还没有执行过的程序,而恰恰return pid就是还没有执行的程序所以父进程执行return,子进程也会执行return

        这就是为什么fork会返回两个返回值的原因。

为什么同一个变量既满足等于0,又满足大于0?

先说结论:因为进程具有独立性,互不影响

        我们可能疑惑虽然说fork返回了两个值,但是都是返回给变量pid。按我们以前的理解,pid应该会进行覆盖,最后只会满足一个条件。但是为什么两个if条件都满足呢?

        首先我们知道,在我们当前这个代码中,父子进程是共享代码和数据的共享代码自然是好理解的,父子进程对代码只有读权限没有写权限,是不能修改代码的

        但是数据呢?假设父进程中有变量a为10,但是如果子进程中要对a进行修改的话,岂不是乱套了?

        所以在不修改数据的情况下,操作系统默认是父子进程共享数据的。但当要修改数据时操作系统就进行“写时拷贝”具体是将需要修改的数据在底层拷贝一份,让目标进程修改拷贝的变量

        所以虽然我们这里的父子进程代码是共享的,但是当fork返回不同的值时,操作系统会进行“写时拷贝”形成父子进程独立的变量pid。父进程执行代码读取的数据与子进程执行代码读取的数据是不同的

        所以最后我们才会看到同时执行了两个输出

由此便解决了我们上述代码中的所有问题

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

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

相关文章

Linux进程间通信(IPC)详解:从入门到理解

引言 作为一名C开发初学者&#xff0c;理解Linux下的进程间通信&#xff08;Inter-Process Communication&#xff0c;简称IPC&#xff09;机制是非常重要的一步。本文将用通俗易懂的语言&#xff0c;配合直观的图示&#xff0c;帮助你理解Linux进程间通信的基本概念和各种实现…

SQL进阶之旅 Day 27:存储过程与函数高级应用

【SQL进阶之旅 Day 27】存储过程与函数高级应用 文章简述 在数据库开发中&#xff0c;存储过程和函数是实现复杂业务逻辑、提高代码复用性和提升系统性能的重要工具。本文作为“SQL进阶之旅”系列的第27天&#xff0c;深入探讨存储过程与函数的高级应用&#xff0c;涵盖其设计…

泰国零售巨头 CJ Express 借助 SAP 内存数据库实现高效数据管理

泰国 CJ Express 运用 SAP 内存数据库有效控制数据增长案例 “Datavard Outboard 操作简便、配置轻松&#xff0c;我们得以在生产系统上完成数据归档&#xff0c;成功将约 730GB 数据迁移至 Hadoop 集群。”——K. Jak&#xff0c;J Express 技术服务经理 关于 CJ Express …

ImageSharp.Web 使用指南:高效处理ASP.NET Core中的图像

文章目录 前言一、ImageSharp.Web简介二、安装与配置1. 安装NuGet包2. 基本配置3. 高级配置 三、核心功能与使用示例1. 基本图像处理2. 处理模式详解3. 自定义处理命令 四、缓存策略1. 物理文件系统缓存2. 分布式缓存3. 自定义缓存 五、性能优化建议六、常见问题解决1. 图像处理…

使用R进行数字信号处理:婴儿哭声分析深度解析

音频信号处理将原始声音数据转化为有意义的洞见&#xff0c;适用于语音分析、生物声学和医学诊断等领域。使用R语言&#xff0c;我们可以处理音频文件、可视化频率内容&#xff0c;并生成如声谱图等详细图表。本指南将展示如何使用R包tuneR、seewave和rpanel分析婴儿哭声音频文…

【环境配置】解决linux每次打开终端都需要source .bashrc文件的问题

解决方法&#xff1a; cd vim .bash_profile输入下面内容后 :wq 保存并退出 # .bash_profileif [ -f ~/.bashrc ]; then. ~/.bashrc fi 参考链接&am…

ResizeObserver的错误

为什么会存在ResizeObserver错误 ResizeObserver loop completed with undelivered notifications. ResizeObserver用于监听元素content size和border size的变化。但是元素的变化和监听可能会导致循环触发&#xff0c;例如有元素A&#xff0c;监听元素A尺寸变化后将元素A的宽…

[k8s]--exec探针详细解析

在 Kubernetes 中&#xff0c;exec 探针是一种通过 在容器内执行命令 来检测容器健康状态的机制。它的核心逻辑是&#xff1a;执行命令后&#xff0c;若命令返回值为 0&#xff08;表示成功&#xff09;&#xff0c;则认为容器健康&#xff1b;否则认为不健康。 一、exec 探针的…

偶数项收敛半径

&#x1f9e0; 背景&#xff1a;幂级数与收敛半径 一个幂级数&#xff08;power series&#xff09;&#xff1a; ∑ n 0 ∞ a n x n \sum_{n0}^{\infty} a_n x^n n0∑∞​an​xn 其收敛半径 R R R 表示该级数在哪些 x x x 的取值范围内收敛。其计算公式&#xff1a; 1 R …

从0开始学习语言模型--Day01--亲自构筑语言模型的重要性

在如今这个时代&#xff0c;人工智能俨然已经成了一个大家耳熟能详的词汇。随着技术的发展&#xff0c;它在不断地降低计算机领域一些工作的门槛&#xff0c;甚至有时候我们能看到一个可能六年前还需要从头开始学习的职业&#xff0c;现在只需要能掌握一个专属的小模型就可以拥…

【量化】策略交易之动量策略(Momentum)

【量化】策略交易之动量策略&#xff08;Momentum&#xff09; 一、动量策略&#xff08;Momentum Strategy&#xff09;原理 &#x1f449;&#x1f3fb; 核心思想&#xff1a; 强者恒强&#xff0c;弱者恒弱。 动量策略认为&#xff0c;过去一段时间涨得多的资产&#xff0c…

Cesium快速入门到精通系列教程九:Cesium 中高效添加和管理图标/标记的标准方式​​

Cesium中通过 ​​Primitive 高效添加 ​​点、线、多边形、圆、椭圆、球、模型​​ 等地理要素&#xff0c;以下是各类地理要素的高效添加方式&#xff1a; 一、公告板 1. 创建 BillboardCollection 并添加到场景​ const billboards viewer.scene.primitives.add(new Ces…

volka烹饪常用英语

1. 视频开场与主题介绍 Today, we are going to learn English while cooking. Fire. In this video, I’m going to continue to teach you the 3,000 most common English words that will allow you to understand 95% of spoken English. And we are going to be preparin…

同旺科技 USB TO SPI / I2C适配器(专业版)--EEPROM读写——B

所需设备&#xff1a; 1、USB 转 SPI I2C 适配器&#xff1b;内附链接 2、24C64芯片&#xff1b; 适应于同旺科技 USB TO SPI / I2C适配器专业版&#xff1b; 烧写EEPROM数据、读取EEPROM数据、拷贝EEPROM数据、复制产品固件&#xff0c;一切将变得如此简单&#xff01; 1…

Linux下成功编译CPU版Caffe的保姆级教程(基于Anaconda Python3.8 包含完整可用Makefile.config文件)

目录 前言 一、环境准备 1. 系统要求 2. 安装必要依赖 二、Anaconda环境配置 1. 安装Anaconda 2. 创建专用Python环境 3. 安装必要的Python包 三、获取Caffe源代码 四、配置编译选项 1. 修改Makefile.config 2. 修改Makefile 3. 修改CMakeLists.txt&#xff08;如…

shell三剑客

了解三剑客 三剑客指的是: grep、sed和awk这三个在linux系统中常用的命令行工具 shell三剑客 grep&#xff1a; 主要用于查找和过滤特定文本 sed&#xff1a;是一个流编辑器&#xff0c;可以对文本进行增删改查 awk&#xff1a;是一个文本处理工具&#xff0c;适合对列进行处…

创客匠人视角:知识IP变现的主流模式与创新路径

知识IP变现赛道正从“野蛮生长”走向“精细化运营”&#xff0c;如何在流量红利消退期实现可持续变现&#xff1f;创客匠人基于服务数万职业教育IP的实践经验&#xff0c;总结出一套兼顾效率与长尾价值的变现逻辑&#xff0c;为行业提供了可参考的路径。 主流变现模式&#x…

【嵌入式人工智能产品开发实战】(二十三)—— 政安晨:将小智AI代码中的display与ota部分移除

政安晨的个人主页&#xff1a;政安晨 欢迎 &#x1f44d;点赞✍评论⭐收藏 希望政安晨的博客能够对您有所裨益&#xff0c;如有不足之处&#xff0c;欢迎在评论区提出指正&#xff01; 目录 本篇目标 第一步 ✅ 修改说明 &#x1f527; 修改后的代码节选 &#x1f4cc; 总…

从sdp开始到webrtc的通信过程

1. SDP 1.1 SDP的关键点 SDP&#xff08;Session Description Protocol&#xff09;通过分层、分类的属性字段&#xff0c;结构化描述实时通信会话的 会话基础、网络连接、媒体能力、安全策略、传输优化 等核心信息&#xff0c;每个模块承担特定功能&#xff1a; 1. 会话级别…

PHP、Apache环境中部署sqli-labs

初始化数据库的时候&#xff0c;连接不上 检查配置文件里面的数据库IP、用户名、密码是否正确 mysqli_connect函数报错 注意要下载兼容PHP7的sqli-labs版本 1、下载sqli-labs工程 从预习资料中下载。 文件名&#xff1a;sqli_labs_sqli-for7.zip 2、配置数据库 把下载好的…