进程管理
进程管理:一个操作系统上,同时跑着这么多的进程,操作系统需要把他们进行管理
管理:
-
先描述:使用一个类/结构体,把这个东西有啥特征都表示出来
-
再组织:使用一个数据结构,把很多个这样的对象/结构体给整理到一起
PCB(进程控制块):就是一个结构体,这个结构体里就包含了一些表示进程的核心信息
操作系统内核中,就把若干PCB串成了一个双向链表
PID:进程的身份标识(类似学号)
内存指针:操作系统要把一些必要的数据加载到内存中(必要的数据有些是要运行的指令(代码),有些是运行时依赖的数据(全局变量))
内存指针就描述了该进程的内存中哪些是指令,哪些部分是数据
文件描述符:表示了当前进程都打开了哪些文件(在代码中打开一个文件fopen,就会在进程的文件描述符表里给这个文件分配一个表项)
这里的文件描述符是一个顺序表的下标,每个元素就代表一个打开的文件,对应的数组下标文件描述符
上述描述了进程持有哪些系统的资源,也认为进程是操作系统中“资源分配”的基本单位
进程的调度
进程里还有一组比较关键的属性,用来实现进程的调度
本质问题:当前计算机的CPU是有限的,但是进程数量是比较多的,所以操作系统就要进行调度,让每个进程都有机会执行
调度其实就是让进程轮流来,这里的轮转速度其实是非常快的(例如:CPU主频是1.9GHz,1s有19亿个时钟周期,时间片轮转)
并发式的执行(宏观上是同时进行的,但在微观上不是同时进行的):由于轮转的速度非常快,所以人感知不到这样的轮转,站在宏观角度,就好像这些进程都在同时执行一样,但是微观上并不是同时,而是“轮流”的方式占用CPU执行
并行式执行(宏观上同时执行,微观上也是同时执行):由于CPU上有多个核心,每个核心上都可以跑一个进程,某一时刻两个进程就是在两个CPU核心上同时执行的
在实际开发中,并不会对这两概念做明确的区分(从人的宏观角度看,看不出区别)往往使用“并发”概括表示“并发”和“并行"
进程的调度相关的因素:进程的优先级,进程的状态,进程的记账信息,进程的上下文
-
进程的优先级:先排谁,后排谁
-
进程的状态:安排的时候要考虑进程的状态
对进程来说有很多的状态,其中最典型的:就绪状态:进程是准备就绪的,随时可以上CPU执行
阻塞状态:进程在等待某个任务完成(读写磁盘),完成后才能上CPU,完成之前,就没法继续执行
-
进程的记账信息:操作系统在安排进程时,也会记录每个进程以往在CPU上执行的时间,如果某个进程被安排得太少,就会适当调整策略(当然这里不一定是看每个进程CPU上的执行时间,也可能是以执行的指令数为单位)
-
进程的上下文:对于进程来说,上下文,具体指的就是CPU里的一堆寄存器里面的值,上下文就会在进程被切出CPU时把寄存器的状态保存在PCB里(内存),等下次进程回到CPU上就把PCB里的上下文读取出来,恢复到CPU寄存器中
这样说进程的上下文可能还不太懂,通俗点讲,就是进程在调度的时候,进程很可能执行了每个操作,执行到一半,就被调度走了,过了一个段时间,进程还是要回来的,回来就需要从之前上次执行到的位置继续往下执行(就跟存档和读档差不多)
进程的虚拟空间地址
进程,需要使用一些系统的资源,其中内存资源就是一个很关键的资源
如果p指到别的进程的内存就很有可能伴随着这个操作就直接把别的进程搞挂了,这种行为就会让整个操作系统都很不稳定。
所以,为了让各个进程之间不要相互干扰,操作系统就引入了“虚假空间地址空间”这样的概念,每个进程都只能访问到自己的地址空间,相互之间不会有影响了,哪怕你指针指错,操作系统也能及时发现,不会影响到其他的进程,就算出问题,问题也被限制到进程的内部。
这里的0~N就是虚拟地址空间
比如进程3里*p=xxx,p就成了野指针,指到错误的地址上了,进行操作p指向的内存时需要经过MMU进行映射,MMU就知道当前访问的是一个有问题的地址,于是就会像操作系统告状:有进程访问内存错了,操作系统就会给对应的进程发一个“信号”,告诉他你的内存访问出错(这个信号的默认处理行为就是让进程终止运行(程序崩溃(比如windows弹个框,提示:xxx,程序已经终止运行了,比如:安卓直接app闪退了)))
因为虚拟地址空间,进程就有了一个重要的特性:隔离性(一个进程的运行一般不会影响到另一个进程,尤其是一个进程崩溃也不会影响到另一个进程)
问:每个进程都有一个虚拟地址空间,你一个系统里进程又这么多,这些虚拟地址空间加到一起,比物理内存大了,可咋办?
答:虽然系统里的进程这么多,但是实际上:1.同一时刻执行的进程没几个
2.即使同一时刻,有好几个进程再跑,这些进程也不是同时把所有的虚拟地址空间的内存都使用上了,假设同时是6个进程再跑,很可能每个进程只使用1M的内存空间,虽然每个进程的虚拟空间很大,但是实际使用的内存只有一小部分,物理内存只需把真实使用的这部分内存数据给表示出来即可
3.极端情况下,确实同时跑的这几个进程同时吃了很多真实内存,确实会导致物理内存不够(出现这种情况,算bug,因此程序员就需要想办法优化,内存占用或者扩容换一个内存更大的机器)
进程间的通信
进程引入了隔离性,确实让系统更稳定了,但是也有别的问题,多个进程之间想配合工作,就麻烦了
所以,操作系统又引入了进程间通信,在隔离性的前提下,开了个口子,让多个进程之间能相互通信
操作系统提供的进程间的通信方式有很多,但是本质上都是一样的,搞一个多个进程之间都能访问到的公共资源,借助公共资源来进行通信