操作系统是一个搞管理的软件
一个应用程序想要操作一下硬件设备。就需要先通过系统调用,把操作系统命令告诉给系统内核,内核调用驱动程序,进一步的操作操作系统
进程包含线程
一个进程包含一个及以上的线程
进程是资源分配的基本单位
线程是系统调度的基本单位
概念:一个跑起来的程序就是一个”进程“
电脑上有一个.exe 可执行程序。但是没有去运行它,没有运行的就不是进程(没有运行起来的叫做程序)
进程(process)也叫做任务(task)
Ctrl + Alt + delete => 打开任务管理器
上面每一个运行中的程序就是进程
每个进程都对应一些资源进程是操作系统资源分配的基本单位
进程调度是指操作系统按某种策略或规则选择进程占用CPU资源进行运行的过程。
硬件资源,内存,硬盘,网卡都好分。但是cup资源不好分!!
进程有上百个之多,但是cpu市面上流行的电脑都是多核cpu,多核大都是8核或者16核。
上图就是一个八核电脑。八核cup和几百个进程明显不够分,狼多肉少。
这些进程,是希望能够同时运行
但是计算机并不能同时运行,计算机真正做到的是分时复用
分时复用分为并行和并发
并行:微观上同一时刻,两个核心上的进程,就是同时进行的
并发:微观上,同一时刻,一个核心中只能运行一个进程,但是它能够对进程快速的进行切换。
比如在cpu核心上,先运行一下qq,再运行一下微信,再运行一下idea…只要切换的速度足够快(我的电脑3.2GHz,每秒运行32亿条指令),宏观上人感知不到,人们看起来感觉好像几个程序在同时运行。就好比电脑屏幕刷新的频率大都是60Hz,屏幕并不是连续的,但是刷新频率大于眼睛的反应,人看电脑屏幕就好像是连续的
并行和并发是由操作系统内核处理的,应用程序(程序员)感知不到,因此我们也把并行和并发统称为并发
除非有显式声明,否则谈到并发,并发 = 并行 + 并发
操作系统里有一个重要的模块调度器,就来负责让有限的CPU来调度执行这么多的进程
进程是一个重要的软件资源,是由操作系统内核负责管理的
管理:组织 + 描述
描述:用结构体(C语言的结构体)来描述进程的属性。
因为操作系统基本上都是C/C++来写的,所以用C语言结构体来描述。
PCB:用来描述进程的这个结构体叫做进程控制块也叫做PCB,这是一个结构体,注意不要和硬件中的PCB板弄混
通过双向链表,把多个PCB串联在一起。(并不是一个单纯的双向链表)
pcb中包含的属性非常非常多,下面只介绍最核心的属性
进程通过调度器对其以并行+并发的形式进行调度。但是它也需要PCB对他提供帮助。PCB就记录进程调度的相关属性。
一个很有名的日本游戏叫做约会大作战,里面的男主角五河士道通过与女生约会来拯救世界。假设现在有ABC三个女生,让男主角和他们约会,还不能让他们相互知到对方的存在就需要合理的安排,但是每个妹子的状态不同,有的妹子暂时有事,有的妹子正在准备和你约会,有的妹子正在和你约会,每个妹子的状态不同所以得记录妹子们的状态,每个妹子不能平均分配时间有的是新攻略的需要多花时间培养感情,有的已经交往了很久有了深厚的感情,就可以先往后放放。每个妹子的约会是有优先级的。和很多女生约会得记录他们的交往的进度和信息,假如A女生说她想去海边旅游了,让你给他准备准备。B女生说亲戚结婚了想让你给她挑一件礼服。但是你没有记录上下文,
A女生问:你准备好了嘛?
主角回答:给你准备了件礼服
B女生问:你准备好了嘛?
主角回答:给你准备了件泳衣
这样就露馅了,所以必须得记录上下文来避免出现错误而导致功亏一篑
主角和ABC交往了一段时间,要每隔一段时间来做个总结,统计一下在每个人身上花费的精力,以此为标准保持好尺度,不能太近也不能太远。
以这个小故事用来理解进程的相关属性
进程的状态主要有下面三种
先给谁排,后给谁排,给谁排的多一点,给谁排的少点。
进程也是有优先级的,操作系统的调度并不是一碗水端平的
操作系统在进行进程切换的时候,就需要把执行的中间状态记录下来,保存好。下次这个进程再上CPU上运行时,就可以恢复上次的状态好继续执行下去。
读档,存档
上下文的本质上就是你存档的内容。
进程的上下文,就是cpu各个寄存器1的值。
保存上下文:就是把这些CPU寄存器的值,记录到内存(PCB)中。
回复上下文:就是把内存中的这些寄存器中的值恢复回去
操作系统,统计每个进程在cpu上的时间和指令数目,根据这个来决定下一阶段如何调度。
进程之间可能会相互影响,
引入虚拟地址空间,地址越界就能及时发现
进程中获取的内存地址,并非是真实的物理内存地址,而是经历了一层抽象,虚拟出来的地址。
在C语言中我们学到了指针的概念,C语言指针指向的也是虚拟地址并不是实际空间地址。
内存(内存物理上是个内存条)可以存储很多数据。内存可以想象成一个大走廊,走廊非常长,有很多房间,每个房间的大小为1byte,每个房间还有编号,从0开始以此累加,这个内存编号就是地址,这个地址就认为是物理地址
内存有个了不起的特性,随机访问,访问内存上任意地址的数据,速度都极快,时间上都差不多,正是这个特点,造就了数组取下标操作时间复杂度是O(1).
假设进程1和进程2分别占据内存空间如上地址,如果进程1的代码不小心出BUG,就可能导致访问的内存就越界了。不小心指变量,变成了0X5000,明明是进程1的BUG却把进程2给搞坏了!!,很可能你的程序一运行qq崩了,百度网盘崩了……
如果代码相安无事还好,一旦出现BUG了,此时的影响非常严重。
针对进程使用的内存空间,进行隔离引入了虚拟地址空间,代码不再直接使用真实的物理地址了,而是使用虚拟地址空间。由操作系统和专门的硬件设备进行虚拟地址到物理地址的转换。
虚拟空间地址,主要是为了避免进程直间的相互影响。
虽然进程隔离了,但是又引入了新的问题。有些时候确实进程之间,需要进行数据的交互。
在隔离性的基础上开个口子。进程通信,实现方法很多,但核心思路是一致的。需要搞一个多个进程都能访问到的公共空间,基于这个公共空间来进行数据的交互即可。
这个就好比与现在疫情期间,有需要隔离的人外面和送餐人员不能直接接触,就需要把食物放在一个公共空间,然后等隔离人员下来就可以在这个公共空间取餐
通过公共空间,来完成进程间的数据交互,使用文件,使用网络
各个寄存器 :CPU内置的存储数据的模块,保存的就是程序运行过程中的中间结果 ↩︎