进程,进程状态,进程切换,程序地址空间

进程,进程状态,进程切换,程序地址空间

冯诺依曼体系结构

存储器:指的是内存,磁盘不是内存,是外存。

输入设备:鼠标,键盘,摄像头,话筒,磁盘(从磁盘文件中读取数据),网卡

输出设备:显示器,播放器,磁盘(保存写好的数据)网卡。

输入输出都是外设设备。有的设备是纯输入,有的是纯输出,有的可输入可输出

运算器:对我们的数据进行计算任务(算数运算,逻辑运算)

控制器:对我们的计算硬件流程进行一定的控制。

运算器与控制器构成了CUP

各个硬件单元必须用线链接起来

总线:系统总线 IO总线

所有的软件都要依靠硬件结构来设计

数据的流动

操作系统

操作系统是一款能够进行管理的软件

为什么需要操作系统?

整个计算机是层状结构,所有的硬件需要被软件访问都需要有驱动程序。操作系统帮助用户,管理好下面的软硬件资源。

为了给用户提供一个良好(稳定,高效的,安全的)运行环境

操作系统通过管理好底层的软硬件资源,为用户提供一个良好的执行环境。

操作系统里面,里面有各种数据,可是操作系统不相信任何用户。

操作系统为了保证自己数据安全,也为了保证给用户能够提供服务,操作系统以接口的方式给用户提供调用的入口。来获取操作系统内部的数据。

所有访问操作系统的行为只能通过系统调用完成。基于系统调用窗口设计各种各样的程序。

怎么办? 如何管理好的?

管理者和被管理者是不需要见面的。

管理者在不见被管理者的情况下,如何做好管理的呢?只要能够得到管理信息,就可以在未来进行管理决策。

管理的本质是通过对 “数据” 的管理,达到对人的管理

管理者和被管理者面都不见,我们怎么拿到数据呢?

进程

进程的定义:

一个已经加载到内存的程序,叫做进程。进程也可以叫做任务。

正在运行的程序叫做进程

一个操作系统不仅仅只运行一个进程,可以同时运行多个进程

任何一个进程在加载到内存的时候,形成进程时,操作系统,要先创建描述进程(用足够多的属性值来描述)的结构体对象。

pcb进程控制块(进程属性的集合)(struct 结构体类型 )

进程的属性有哪些: 进程编号

​ 进程状态

​ 优先级

描述该进程的PCB以及该进程的数据和代码,一起组成了进程。

创建描述进程的结构体对象,将可执行程序的二进制代码和数据加载到内存当中,同时创建pcb对象。

进程就是描述该进程的pcb对象,加上可执行程序的二进制代码和数据。

在这里插入图片描述

管理进程是管理pcb对象。PCB里面包含很多属性。

pcb包含相关的指针信息:包涵进程的代码和数据的位置,通过指针来找到。

操作系统内有多个进程,操作系统通过对pcb的管理进而完成了对进程的管理。

linux是如何组织进程的呢?

linux内核中最基本组织进程task_struct的方式,采用双向链表组织的。

task_struct就是pcb在Linux中

程序计数器:记录当前指令的下一条指令的位置,当进程中断,再次运行的时候可以找到指令的位置。

这里是通过管道文件,只显示一行

在这里插入图片描述

想要连续执行多条命令,每个命令中间可以使用&&符号相连接

在这里插入图片描述

PID是每个进程独有的信息。

查看进程相关属性的方法:

ls /proc目录

proc目录关机以后这个目录就没有了,它只是内存级的。开机以后又自动创建。

所有的指令都变成了进程

进程有工作目录

这里的蓝色数字代表的是进程的pid,当一个进程被加载到内存时,就会在proc目录下创建这样的一个目录。

在这里插入图片描述

目录里面包含了这个进程的所有属性。

进程在启动时会自动记录进程所在的位置。

ps命令查看进程

在这里插入图片描述

查看进程的信息

在这里插入图片描述

kill -9 杀掉这个进程

在这里插入图片描述

PID为了区分每一个进程,我们对每一个进程加上了PID

进程的pid放在struct task_struct结构体中。

getpid系统调用接口

这个函数,谁调用这个函数,就返回这个进程的PID

在这里插入图片描述

bash是所有进程的父进程。

PPID就是父进程的pid。

fork为什么要给子进程返回0,给父进程返回子进程的pid?

在这里插入图片描述

返回不同的返回值,是为了区分让不同的执行流,执行不同的代码块

fork之后父子代码共享,只是执行不同的部分

fork要给子进程返回0,给父进程返回子进程的pid

fork是如何返回两个的值呢?

return语句也是代码,也是属于父子共享的,当被调用时会被返回两次。发生了写时拷贝

fork干了什么事情?

fork之后创建了一个新的进程,共享代码,所以会执行两遍相同的代码。

在走到return语句之前父子进程都已经创建好了,所以return语句是代码,是两个进程共享的。

在任何平台,进程在运行的时候是具有独立性的

一个进程运行崩溃了,不影响其他的进程。

因为数据可能被修改,不能让父子进程共享一份数据。

所以写时拷贝,当子进程想要对共享的数据做修改时,操作系统会开辟空间,并且复制一份,让他进行修改。

因为发生了写时拷贝,在return语句时,都是写入,所以数据会发生变化,所以会拷贝两份。

子进程被创建出来谁先运行呢?

由调度器决定,谁先运行是不确定的。

调度器是什么东西?

调度器的调度原则是尽可能保证平衡和公平

进程状态

运行状态 R状态

在这里插入图片描述

只要在运行对列就是运行状态

每一个进程都有时间片的概念,当时间片结束进程久从cpu上下来。

在一个时间片内,所有进程代码都会被执行!并发执行。

大量把进程从CPU上放上去到拿下来的过程叫做进程切换。

阻塞状态 S状态

软硬件资源没有就绪,只能在等待队列中等待,等待数据。

在这里插入图片描述

阻塞状态就是在等待队列内。有非常多的等待队列,需要等待哪里的资源,进程就链入到对应的等待队列内就行。

比如bash就是等待状态,bash一直在等待用户输入,所以也是在等待队列。

挂起状态

当操作系统内部内存资源严重不足了,保证正常的情况下,省出来的内存资源, 将PCB放在队列里面排队,代码和其他的资源仍然放在外设中。 就是pcb在等待对列内,然而代码和数据放在磁盘内。

这就是挂起状态。

这个程序正在运行,但是这里是S状态,为什么呢?

其实是cpu的速度很快,我们的程序需要打印,进程一直等待显示器资源。所以一直显示s状态。如果把打印去掉,就显示R状态了。

在这里插入图片描述

如果没有加载就触发缺页中断。当进程被加载到cpu时,并不会将所有的数据都全部加载到内存,因为运行到执行或者需要这部分数据时还需要花费一定的时间,计算及不会做浪费资源的行为,所以一次只加载进程的一部分数据。

D状态(深度睡眠)不能被杀死,进程必须被执行完。

不响应任何请求。

也是阻塞状态。S状态被称为浅度睡眠,是可以被唤醒的。随时可以响应外部的变化。

T状态(stopped)暂停状态

在这里插入图片描述

这些信号可以管理进程。

sleep状态与暂停状态,暂停状态可能不是等待某些资源而是仅仅想让他暂停运行。

Z状态:僵尸状态

进程在退出时,并不会立马将它释放,操作系统将会维持一段信息,直到父进程获取后,在将它释放,进入X状态,就是死亡状态。

父子进程,父进程先退出,子进程的父进程会被改为1号的进程(操作系统),父进程是1号进程,孤儿进程。该进程被系统领养。孤儿进程未来也需要退出,也要被人回收。

进程的优先级

进程被创建出来,而且有父子关系,注定了进程的pcb结构就是一颗多叉树的结构。

多叉树中的一个节点,可能还链入到链表或者对列当中,是一种复杂的数据结构。

操作系统内各个pcb的链接是通过struct node结构体链接,它放在pcb的内部,当需要访问某个位置的数据时,计算struct node的偏移量即可访问到相应的数据。

在这里插入图片描述

权限决定的是能不能,优先级决定的是这个资源谁先谁后访问。

为什么要有优先级?

进程太多了,cpu只有一个,因为资源是多个的,注定了是竞争性。

操作系统是必须保证大家良性竞争。确认优先级,

在这里插入图片描述

PRI就是优先级。NI这个是进程优先级的修正数据。进程的优先级是可以修改的,通过修改NI值就可以修改进程的优先级。

每一个进程都有一个叫做:时间片的概念

把进程放到运行队列里面就是运行状态了。

大量把进程放上去取下来的操作叫做进程切换。

有加号是进程在前台运行,没有加号代表在后台运行,前台运行的程序可以直接用CTRL + c 终止

后台运行的程序只能用kill - 9 XXXX 才能终止

kill -19 使得目标进程暂停

kill -18使得目标进程继续

在这里插入图片描述

PRI表示这个进程的优先级

NI表示优先级的修正数据

linux不想让用户过多的参与优先级的调整,在我们对应的范围内进行优先级的调整。

nice指令,renice指令修改优先级

top更改优先级,普通用户不能调整。

old默认是从80开始的,永远都是80不管从哪个优先级开始。

位图

在这里插入图片描述

并行:多个进程在多个cpu下分别,同时进行运行,这称为并行

并发:多个进程在一个cpu下采用进程切换的方式,在一段时间内,让多个进程都得以推进,称为并发。

进程切换

一般是两个进程对列,进行维护,切换,轮转调度,一个调度完,调度下一个。

进程是如何切换的呢?

为什么返回值会被外部拿到呢?返回值也是局部变量

CPU内部有大量的寄存器,函数的返回值保存在寄存器当中。

return a -> mov eax 10 会放到某个寄存器当中,然后再把寄存器的值返回给调用者。

系统如何得知我们的进程当前执行到那行代码了?

系统是通过程序计数器,pc指针,指向代码的指针,eip,记录当前进程记录当前进程正在执行指令的下一行指令的地址。

寄存器具有对数据进行临时保存的作用,为了提高效率,将进程的高频数据放入寄存器中,cpu里面保存的是进程相关的数据。

程序计数器pc /eip:记录当前进程正在执行指令的下一行指令的地址

寄存器种类:

指令寄存器

通用寄存器,eax ebx ecx edx

栈帧结构 ebp esp eip

状态寄存器 status

cpu中寄存器的作用:提高效率,将进程的高频数据放入寄存器当中

cpu内的寄存器保存的数据是进程相关的数据,随时随地被cpu访问修改

进程在从CPU离开时,要将自己的上下文数据保存好,甚至带走,保存的目的是为了恢复。

进程在被切换时 1.保存上下文 2.恢复上下文

cpu上的临时数据放在进程的pcb里面。

环境变量

环境变量PATH:linux的指令搜索路径

env 查看所有的环境变量。

getenv()函数可以获取环境变量。

环境变量具有全局属性

环境变量是系统提供的一组name = value形式的变量,不同的环境变量有不同的用户,通常具有全局属性。

int main(int argc,char* argv[],char* env[])
{};

env数组是一个指针数组,将环境变量作为参数传入。

两个核心向量表:命令行参数表。环境变量表。

我们所运行的进程,都是子进程,bash本身在启动时,会从操作系统中的配置文件中读取环境变量信息,子进程会继承父进程交给我们的环境变量。

系统当中针对指令文件的搜索是有环境变量。

在这里插入图片描述

为什么我们运行自己的程序需要添加./ 指定路径,而指令运行时却不用添加呢?

PATH:Linux系统的指令搜索路径

在这里插入图片描述

这样写是将环境变量的路径整体替换掉了

在这里插入图片描述

新增路径,环境变量新增。

重新打开shell即可重新加载环境变量,不用担心配置错了

env查看所有的环境变量

SHELL

USER

HOME

环境变量是系统提供的一组name = value 形式的变量,不同的环境变量有不同的用户,通常具有全局属性

命令行参数

main函数可以带参数

argc保存的是argv这个数组一共有多少个元素。

argv指针数组

我们在命令行输入的其实就是字符串,xshell会将字符串分割,每个都传给我们的mian函数,以命令行参数传递给argv。

这就是指令的解析

在这里插入图片描述

指针数组
在这里插入图片描述

以空格作为分割符。

为什么要这样做?

为指令,工具,软件提供命令行选项的支持。

在这里插入图片描述

我们所运行的进程都是子进程,bash本身在启动的时候,会从操作系统的配置文件中读取环境变量信息,子进程会继承父进程交给我的环境变量。

main(int argc,char argv[],char* env[]);

本地变量与内建命令

本地变量指的是在命令行可以直接定义的变量,本地变量只会在本bash内部有效,不会在子进程中继承

命令行上启动的命令并不是都会创建子进程

常规命令:通过创建子进程完成

内建命令:bash不创建子进程,而是自己亲自执行, 类似于bash调用了自己写的,或者系统提供的函数。

cd就是内建命令

env

export 之后就变成环境变量,就可以继承给子进程。

echo都是内建命令

程序运行需要两张表:一个是命令行参数表 一个是环境变量表 由系统维护(bash维护也可以)

main函数也是函数也会被调用和传参,会被系统调用,将两张表传输进去

程序地址空间

研究背景:

pid_t id = fork();
if(id ==0)

else if (id > 0)

fork()的返回值是两个,但是id变量只有一个,怎么可能同时执行,虽然有写时拷贝,但是理解还是不够透彻。

两个进程对应的虚拟地址是一样的,但是对于不同进程的页表对应的物理地址是不一样的。

在这里插入图片描述

堆栈相对而生,堆区是向地址大的方向增长,栈区是向地址空间小的方向增长。

static变量只作一次初始化,随着函数调用也不会释放。

数据段是用于存储静态变量、全局变量和字符串常量等数据的内存区域。

在这里插入图片描述

怎么可能同一个变量,同一个地址,同时读取,读到了不同的内容呢?

结论:如果变量的地址是物理地址,是不能存在上面的现象

所以他不是物理地址!!!

线性地址&&虚拟地址

C / C++用的指针,指针里面的地址不是物理地址。

C++程序员如何看待内存?

进程地址空间就是上面绘制的图,每一个进程在创建时都会提供一个这样的图。

物理内存

父进程要创建子进程时,系统当中创建子进程就是创建了一个进程,创建他自己的内核pcb结构,子进程基本上以父进程为模板,子进程被创建出来以后,也要有进程地址空间

在这里插入图片描述

这里改变的是物理地址,重新在物理内存中开辟了新的地址,将子进程的虚拟地址重新指向新的物理地址。

地址空间究竟是什么?

本质是一个描述进程可视范围的大小

地址空间内一定存在各种区域划分,对线性地址进行start,和end即可

你的地址排列组合形成的地址范围 [ 0 , 2^32 ]

如何理解地址空间上的区域划分?

32位计算机中,有32位地址和数据总线。

地址总线和数据总线:每一根总线, 有两种状态,高电平和低电平,cpu在向内存中充电,

一共有32根,从cpu中出去一共有2 ^ 32 中, 就是4GB内存空间。

地址空间本质是内核的一个数据结构对象,类似PCB一样,地址空间也是要被操作系统管理:先描述,在组织。

在这里插入图片描述

创建一个进程时,会创建pcb的同时创建上面的结构体对象,默认划分区域是4GB

所以什么叫做进程?以及进程地址空间?为什么要有?

1 让所有进程以统一的视角去看待内存 – 为什么?

2 增加进程虚拟地址空间可以让我们访问内存的时候,增加一个转换的过程,在这个转换的过程中,可以对我们的寻址请求进行审查,所以一旦异常访问,直接拦截,该请求不会到达物理内存,保护物理内存。

每一个进程都有自己的进程地址空间,每一个进程都要划分一段地址空间。

页表是一种软件结构

在系统当中,cr3寄存器,保存当前进程页表的起始地址。cr3本质上属于进程硬件的上下文。进程不运行被切换走了,寄存器的内容也会被带走,当再次运行时,会重新加载出来。

页表的地址是物理地址

页表当中还有标志位,用来看这个数据是可读还是可写。查看虚拟地址对应的物理地址是否为可读可写。

页表可以提供很好的权限管理。在页表的位置判断你是只读还是可写。

在这里插入图片描述

进程是可以被挂起?

你怎么知道进程被挂起了,linux没有挂起状态,你怎么知道你的进程的代码和数据在不在内存呢?

共识:现代操作系统不做任何浪费任何空间和资源的行为。

我们的操作系统可以对大文件进行分批加载。

假设我们加载了500kb的空间,但是我程序是一行一行跑,只用了10kb的空间,所以变性的浪费。

程序加载的方式:惰性加载

就是用多少加载多少

页表还有一个位置,标志着对应的代码和数据是否已经加载到内存。

如果没有加载,会触发一个词:缺页中断。

写时拷贝也是缺页中断。

创建一个进程,不加载数据跟代码是可以的,在真正运行时在加载时完全可以的。

先创建内核数据结构,PCB,地址空间,页表。处理好。再加载程序。

可能程序一瞬间就跑起来了,但是可能程序还没有加载完成。

linux内存管理模块。

进程知道当前内存的状态吗。不知道。

在这里插入图片描述

有了页表和进程地址空间的存在,将进程管理和内存管理模块进行解耦合。

什么叫做进程呢?

进程 == 内核数据结构(task_struct && mm_struct && 页表) + 程序的代码和数据。

在这里插入图片描述

img-lgErL3zY-1715154947075)]

进程是可以被挂起?

你怎么知道进程被挂起了,linux没有挂起状态,你怎么知道你的进程的代码和数据在不在内存呢?

共识:现代操作系统不做任何浪费任何空间和资源的行为。

我们的操作系统可以对大文件进行分批加载。

假设我们加载了500kb的空间,但是我程序是一行一行跑,只用了10kb的空间,所以变性的浪费。

程序加载的方式:惰性加载

就是用多少加载多少

页表还有一个位置,标志着对应的代码和数据是否已经加载到内存。

如果没有加载,会触发一个词:缺页中断。

写时拷贝也是缺页中断。

创建一个进程,不加载数据跟代码是可以的,在真正运行时在加载时完全可以的。

先创建内核数据结构,PCB,地址空间,页表。处理好。再加载程序。

可能程序一瞬间就跑起来了,但是可能程序还没有加载完成。

linux内存管理模块。

进程知道当前内存的状态吗。不知道。

有了页表和进程地址空间的存在,将进程管理和内存管理模块进行解耦合。

什么叫做进程呢?

进程 == 内核数据结构(task_struct && mm_struct && 页表) + 程序的代码和数据。
在这里插入图片描述

  • 11
    点赞
  • 30
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值