深入理解Linux进程:体系结构、进程管理与fork()原理解析
文章目录1. 冯诺依曼体系结构1.1 体系结构的基本组成1.2 数据的流动与效率2. 操作系统2.1 操作系统的概念2.2 设计操作系统的目的2.3 核心功能2.4 如何理解管理2.5 系统调用和库函数3. 进程3.2 进程结构的属性3.3 查看进程3.4 如何创建进程子进程3.5 fork()的深入理解3.5.1 fork()的三个核心问题3.5.2 fork()的写时拷贝机制1. 冯诺依曼体系结构1.1 体系结构的基本组成存储分级的问题体系结构效率问题程序要运行必须先加载到内存中一个计算机以内存为主就可以让普通人以较低的价格获得效率不错的计算机。冯诺依曼机为电脑提供性价比被人们广泛接受。程序的本质是逻辑数据在数据层面CPU不和外设之间打交道只会和内存打交道。为什么体系结构规定的。结论在数据层面上CPU不会和外设之间打交道CPU读写数据只会和内存打交道我们口中的输入输出是站在内存的角度思考问题也就是站在加载到内存中的程序的角度也就引出了我们的I/O。1.2 数据的流动与效率计算机数据流动的过程本质就是拷贝。计算机的效率问题本质就是由设备的拷贝效率决定的离CPU越近效率越高。数据的运转实际上就是数据的拷贝存储设备的效率本质上就是拷贝的效率。文件传送你往云服务器上拖拽文件实际上是将在你硬盘上的数据拷到你买的云服务器的磁盘上。数据的流动和软件没有关系路怎么修数据就怎么走。2. 操作系统2.1 操作系统的概念任何计算机系统都包含一个基本的程序集合称为操作系统OS操作系统包括内核四大功能进程管理内存管理文件系统设备驱动其他程序例如库函数shell程序等2.2 设计操作系统的目的操作系统的设计目的可以总结为一个手段一个目的手段对下与硬件交互对计算机所有的软硬件资源进行合理、高效的管理。目的对上为用户程序应用程序提供一个稳定、安全、高效的执行环境。就像一家餐厅老板必须管理好底下的服务员、厨师和硬件设施手段最终目的是为了给顾客提供优质的就餐体验目的。如果操作系统管理不好导致电脑频繁死机用户就会选择卸载它。2.3 核心功能既然操作系统的本质是管理那它具体管理什么呢在冯诺依曼体系结构下主要包含以下四大核心管理模块进程管理管理程序的执行过程创建、调度、终止进程等。内存管理管理内存空间的分配、回收以及虚拟内存的映射。文件系统管理磁盘上的数据提供文件的创建、读写、删除等接口。设备驱动管理各类外设如键盘、鼠标、网卡、磁盘等屏蔽硬件底层的复杂性。2.4 如何理解管理管理的本质实际上是对数据进行管理数据的本质是提供决策依据的。操作系统是一款软件是一款进行软硬件资源管理的软件它的底层逻辑实际是先描述再组织校长操作系统内核老师驱动程序学生底层硬件站在数据结构的角度去理解OS内部最核心的东西是什么是数据结构那么引出了C语言中为什么会有类和STL类的本质是描述STL的本质是组织形式。先描述再组织是这个世界的真相是把现实世界的问题进行计算机建模的核心规律。2.5 系统调用和库函数操作系统是怎样对上管理的通过系统调用。很多C/C函数都是对系统调用的封装。所有涉及到硬件的操作都需要通过系统调用贯穿操作系统。库函数和shell程序都是间接地通过系统调用来完成的。3. 进程课本中是怎样描述进程的呢进程运行起来的程序内存中的程序。程序和可执行文件是一回事程序的本质是磁盘上的一个普通文件。什么叫做进程呢操作系统内能同时运行很多程序每个程序都要加载到内存。操作系统内一定会同时存在很多进程这些进程要不要被操作系统管理起来当然要。在我们还没有启动进程之前第一个软件是什么是操作系统。操作系统应该如何管理进程在操作系统内先描述一个进程需要有一个数据结构。如何证明这个进程属于操作系统首先进程要在操作系统里其次里面要有描述你的属性信息的结构体。实际上进程 内核数据结构 自己程序的代码和数据程序就是在磁盘特定路径下的文件。执行命令的本质就是启动进程。启动APP的本质也是启动进程。gcc-otext.c text的本质也是进程这个进程的任务是将源文件翻译为可执行文件。3.2 进程结构的属性标识符描述本进程的唯一标识符用来区别其他进程状态任务状态退出代码退出信号等优先级相对于其他进程的优先级优先级实际上就是一个整型变量。存在优先级的本质是资源竞争程序计数器程序中即将被执行的下一条指令的地址。执行代码不是一口气执行完的和进程切换有关内存指针包括程序代码和进程相关数据的指针还有和其他进程共享的内存块的指针上下文数据进程执行时处理器的寄存器中的数据记录你执行到哪里了保存的就是寄存器中的临时数据。CPU内的寄存器只有一份但上下文可以有多份分别对应不同的进程属于进程私有一个进程执行代码占有CPU把自己的代码执行完才放弃CPU吗不是。当代计算机都会给每个进程分配一个时间片时间片执行完毕就自动让出CPU让另一个进程执行。所以一个进程没有执行完就可能会把CPU让出去。基于时间片的轮转调度因为时间片到达就会存在时间片的切换和调度的动作。I/O状态信息包括显式的I/O请求分配给进程的I/O设备和被进程使用的文件列表记账信息可能包括处理器时间总和使用的时钟数总和时间限制记账号等3.3 查看进程上下文数据放到PCB里临时数据保存在内核栈中。一个进程如何获得自己的标识符获取自己的task_struct结构内部的属性值OS就必须给我们提供一个系统调用。mangetpid通过系统调用将里面的结构复制一份出来。执行第一行代码的时候就有id了打印一下看看psaxj|grepprocess加上列信息的提取psaxj|head-1紧接着再执行psaxj|head-1;psaxj|grepprocessPID是不一样的计数器默认是线性递增的分配完了会回绕。但是其他任务也在用所以你看到的没有特定的规律。一个进程除了有自己的PID还有一个父进程获取父进程getppid();在Linux系统中新的进程往往是通过父进程的方式创建出来的。问题是父进程是怎样创建子进程的每一次启动自己的PID一直在变但是自己的父进程一直不变。所以父进程是谁啊自己的程序、执行命令本质上都是将命令名交给bashbash是我们之前说的命令行解释器它会给我们创建子进程它是所有程序的父进程。命令行解释器本身就是一个进程我们最常见的父进程就是bash。3.4 如何创建进程子进程通过代码的方式创建子进程创建进程的本质是系统多了一个子进程 → task_struct 代码和数据。创建一个子进程必定要经过系统调用也就是使用fork()可以创建一个进程。#include stdio.h #include unistd.h int main() { printf(before fork\n); pid_t id fork(); if(id 0){ // child printf(child: pid%d, ppid%d\n, getpid(), getppid()); } else { // parent printf(parent: pid%d, child pid%d\n, getpid(), id); } sleep(1); return 0; }一个printf被打印了两次fork之前只有一个执行流fork之后执行流被一分为二一个延续另一个创建了一个子进程。实际上就是通过系统调用fork创建一个子进程。bash解释器是用C语言写的bash里面也是通过fork()创建进程的。/proc目录内部包含很多用数字命名的目录每个数字代表一个进程的PID进程信息可以让我们以文件的形式实时展示出来。进程存在则目录存在进程结束则目录消失。进程会实时在/proc目录下显示文件内容是进程所对应的属性查出来的结果是从文件里面筛选出来的。一个进程的属性里面会存在一个cwd当前工作目录。3.5 fork()的深入理解3.5.1 fork()的三个核心问题问题1为什么给子进程返回的是0给父进程返回的是子进程的PID父进程可以有多个子进程需要通过每个子进程的PID来区分和管理它们。而子进程只需要知道自己是否创建成功即可如果需要知道父进程的PID可以通过getppid()随时获取。这种设计让父进程和子进程能够通过返回值轻松区分彼此便于编程。问题2fork()一个函数怎么会有两个返回值普通函数只有一个返回值但fork()是系统调用。调用时进程进入内核态内核完成进程复制后在返回用户态时父进程和子进程各自从内核返回一次各自得到一个返回值。所以看起来“一个函数返回了两个值”。问题3一个id变量怎么能接收两个不同的值即等于0又大于0父进程和子进程的id变量在虚拟地址空间中是相同的但它们映射到不同的物理地址通过写时拷贝机制。子进程得到的返回值是0父进程得到的返回值是子进程的PID分别写入各自独立的物理内存中。因此同一个变量名虚拟地址相同可以存储不同的值物理地址不同。3.5.2 fork()的写时拷贝机制fork()创建子进程时子进程复制父进程的页表父子进程的页表项都被标记为只读父子暂时共享同一块物理内存当任一进程尝试写入时触发缺页中断操作系统为新进程分配新的物理页框将原数据拷贝到新页框中更新页表映射恢复读写权限这就是写时拷贝Copy-on-Write机制它让fork()创建进程的效率极高只需要复制页表不需要复制全部物理内存。欢迎大家批评指正