【Linux系列】并发世界的基石:透彻理解 Linux 进程 — 理解操作系统
👓️博主简介:
文章目录
- 前言
- 一、冯诺依曼体系
- 二、操作系统(Operator System)
- 2.1、概念
- 2.2、设计OS的目的
- 2.3、核心功能
- 2.4、如何理解管理
- 2.5、系统调用和库函数的概念
- 总结
前言
我们在了解系统之前,我们得先来了解了解什么是操作系统,我们的进程便是在操作系统的基础上诞生的,所以对操作系统的学习和了解是非常重要的,它是我们的根基,本章节就来粗略的看看操作系统到底是什么,在往后的学习中,我们对操作系统的学习会逐渐加深。我们一起来看看吧。
一、冯诺依曼体系
我们常见的计算机,如笔记本等,以及我们不常见的计算机,如服务器等,大部分都遵循冯诺依曼体系,冯诺依曼体系结构是计算机的物理骨架。
截止目前,我们所熟知的计算机都是由各种硬件组件组成:
- 输入单元:包括键盘、鼠标、话题、摄像头、写字板、磁盘(也叫外存)、网卡等;
- 中央处理器(CPU):含有运算器(包括加减乘除等的算数运算 及 真假等的逻辑运算)和控制器等;
- 输出单元:显示器,打印机、磁盘、网卡等;
磁盘:
- 也叫外存(外部存储器);
- 在我们(使用 C++ 时)访问文件(读或写)的时候本质上就是把磁盘的数据读到内存里,或者把内存的数据写到磁盘中,也称IO(Input/Output);
- 在硬件中,我们是站在存储器(内存)的角度来理解 IO 的,写入内存的操作就是 Input、写出内存的操作就是 Output;
冯诺依曼体系学习的必要:
为什么软件的运行,必须先加载??
答案就是体系结构的规定;
- CPU 获取,写入,只能从内存来进行!
- 软件的运行,本质上就是 CPU 在执行我们的代码,访问我们的数据;
- 程序运行之前存在磁盘 -> 文件中;
- 加载的本质就是 Input:将外设的数据 Input 到我们的存储器;
本质就是 CPU 无法直接读取外设,所以就只能通过加载才能让我们的程序被 CPU 访问到;
数据是如何流动的??
本质是数据的拷配: 数据从一个设备 “ 拷配 ” 到另一个设备就实现了流动;
也就是说体系结构的效率取决于设备的 “ 拷配 ” 的效率!!
冯诺依曼体系为何如此??
冯诺依曼体系为什么要这个样子,难道就不能直接 CPU 和外设在一起,这样就不用有 “ 拷配 ” 这一步骤来消耗时间了?
答案肯定是不行的,这里就涉及到存储分级的概念了。
在图中以及我们的知识可以知道,在计算机世界中,存储这件事情,如果是离 CPU 越近,那它的存储容量往往越小,但是存储的效率越快;反之离得越远,它的存储容量越大,但是存储的越慢;同时离得越近越贵、越远越便宜。
那为什么不能像上图那样设计冯诺依曼体系呢?主要是外设的效率和 CPU 效率不匹配!假如我们的文件输入或输出的效率是毫秒(1 * 10-3 s)级别的,那我们 CPU 处理效率就是纳秒(1 * 10-9 s)级别的,整整差 1 * 106 s;这样就会出现我们的输入设备把数据 “ 拷配 ” 给 CPU,CPU 一下子就处理完了后把数据 “ 拷配 ” 给输出设备;也有可能 CPU 和输出设备一直在等输入设备处理数据的情况;就会导致 CPU 一直在等待状态;这就会导致我们的体系结构的效率就完全由外设来决定了。
但是这种改版的冯诺依曼体系也不是不能使用,把我们的存储设备全部改成寄存器就可以了,这样当然是没有问题的,但是架不住烧钱啊,1TB 的内存可能就一两百,但是好点的 4G 的寄存器都可能五六百了;如果要容量足够大,那得要多少钱啊。
为了让我们的计算机造价降下来,我们便在冯诺依曼体系结构中引入内存,拥有内存后,我们输入输出的数据就可以提前放到内存中,使得外设和 CPU 之间的速度不匹配做一定的适配。这样就可以用较少的钱获得一台较不错的计算机。
冯诺依曼体系的历史意义:
当代的计算机在冯诺依曼体系下是性价比的产物,是计算机的主流结构;它使我们的用户通过较低的价格就能得到一个性能还不错的计算机,这使得全世界很多普通人能买得起计算机,才慢慢产生互联网,冯诺依曼体系是我们构建互联网的必要条件。冯诺依曼体系的存在是历史选择的产物。
理解数据流动:
假如生活在北京的你想要通过QQ联系一名在南京的朋友,在这之中数据是如何流动的?
由于使用的是计算机,所以本质上就是两个冯诺依曼体系之间的交互。
我们用户在打开QQ时相当于在内存中加载QQ这个文件,所以QQ在内存中,后我们的信息通过QQ的文件在CPU中加密打包后再通过网卡发送出去,在南京的朋友的QQ文件中通过CPU进行解密后显示在显示器上,这就是数据流动的全过程。发送文件也是同理。
硬件是软件的骨架,通过站在硬件的角度,我们就可以理解我们很多觉得匪夷所思的事情。
物理结构决定应用表现!!
关于冯诺依曼,必须强调几点:
- 这里的存储器是指内存;
- 不考虑缓存的情况下,这里的 CPU 能且只能对内存进行读写,不能访问外设(输入或输出设备)(CPU 在数据层面只和内存打交道);
- 外设(输入或输出设备)要输入或输出数据,也只能写入内存或者从内存中读取(外设在数据层面也只和内存打交道);
- 所有的设备都只能直接和内存打交道;
二、操作系统(Operator System)
2.1、概念
任何计算机都包含一个基本的程序集合,称为操作系统(OS)。笼统的理解,操作系统包括:
- 内核(进程管理、内存管理、文件管理、驱动管理)
- 其他程序(例如函数库、shell程序等等)
*操作系统是一款进行软硬件管理的软件!!
*
操作系统一般称为狭义上的操作系统和广义上的操作系统,一般狭义上的操作系统我们称之为操作系统的核心,也就是内核;例如 window 内核、Linus 内核等;如果只有内核,我们用户是使用不了的,所以在其基础上产生了各种其他程序,比如开发操作系统就有各种函数库,为了能用操作系统,给我们提供了命令行及图形化界面。广义上讲就包含了操作系统内核及在内核上安装的外壳程序等。
2.2、设计OS的目的
- 对下,与硬件交互,管理所有软硬件资源(不是目的,是手段);
- 对上,为用户程序(应用程序)提供一个良好的执行环境(为用户提供好的服务是目的);
底层硬件是通过冯诺依曼体系结构连接在一起的,驱动程序是用来给不同的硬件访问的,网卡有网卡驱动,硬盘有硬盘驱动,其他的硬件也有相应的驱动程序,如果用户想要读取如键盘、鼠标等这些设备上的数据。不同的设备都要有自己个性化的读取方式,用户访问不同的设备就得使用不同的驱动程序。在驱动程序上就有了我们的操作系统。
注意:
-
软硬件体系结构为层状结构(硬件,驱动系统,操作系统各自一层);
-
在软件工程上体现为高内聚(相同功能、逻辑的代码放在同一层内部,如操作系统内全是操作系统代码和数据、驱动程序内全是驱动程序的代码和数据),低耦合(层和层之间通过一些接口的方式来调用,在数据和逻辑层面没有强耦合的联系)。增加代码后期的可维护性(联想封装、继承和多态);
-
在硬件层面上同样体现为高内聚、低耦合。用户可以随时更换各种零部件而没有限制、更换后依然可以和别的硬件一块使用等。
-
访问操作系统,必须使用系统调用 – 其实就是函数,只不过是系统提供的(操作系统不允许用户直接访问内存、直接读取进程、直接访问文件、直接读取驱动,必须使用操作系统自己提供的 C 封装的接口,我们称这种接口叫做系统调用);
-
printf 的本质:是你把你的数据写到了硬件 -> 显示器!并不是直接把我们的 C 文件要输出的内容直接写到硬件上。我们的整个操作系统是层状的,我们不可能绕过操作系统直接写到硬件上,所以说 printf 函数本质上一定在底层封装了系统调用,然后操作系统对驱动进行访问,后驱动再把数据交到硬件上后通过显示器打印出来。
-
我们的程序如果你能判断出访问了硬件,那么它必须贯穿了整个软硬件体系结构!!
-
库可能在底层封装了系统调用(平时我们的操作都是在用户层进行的,无论是开发、指令和管理操作,全部都必须通过应用程序转化成系统调用接口);
2.3、核心功能
在整个计算机软硬件框架中,操作系统的定位是:一款纯正的“ 搞管理 ”的软件;
2.4、如何理解管理
- 管理的例子 - 学生、辅导员、校长;
- 描述被管理对象;
- 组织被管理对象;
举个例子:
在我们的学校当中有着各色各样的角色,比如辅导员、学生、校长、学生会、领导等。我们把其简化成只有学生和辅导员及校长。
我们的学校要维持学生们的正常生活,所以要将我们学生管理起来。
在这个模型中,学生很显然是被管理者,校长是管理者,辅导员充当执行者;
在我们的体系当中,我们人在日常生活中要做的事情无非两种:
- 决策(要参加高考、要吃饺子等);
- 执行(参加高考、吃饺子等);
一般我们决策和执行是不分家的,也就是即在做决策、也在做执行,在我们学校的体系中,我们的管理者和被管理者的最大区别就是管理者有决策权,我们学生只能被动的接受管理者的决策;在一个管理体系里,我们的管理者只负责决策,真正的执行者往往由中间层决定;我们的辅导员是没有决策权的,他们所作的所有工作都是来自于校方的决策。回过头来看我们的 OS 结构。
那我们怎么做管理呢??
当我们在小学的时候时,加起来都没有几个小学生,这个时候就不在区分校长和辅导员,管理起来也很方便。等到年纪大了些,上了大学,我们的学生数量多了起来,管理起来就十分的困难,就不得不产生辅导员。首先我们有一个疑问,如果一个人相对另一个人进行管理,是否需要与其见面?
我们可能大抵是经历过上大学没有见过校长、上班没有见过老板的情况。但是我们要放多少假期、要领多少工资,有没有年终奖等。都被安排的明明白白。由此可以得出第一条:
要管理,管理者和被管理者可以不需要见面;
但是如果他们连面都不见又是怎么管理的呢??
我要去看看你是不是没有起床,想要知道你是不是考试没有及格,我想要知道你上课时间在不在宿舍等。见面不是本质!!我只需要知道你的学分是不是 4.0 以上,我就能决策你是不是好学生;辅导员说你在上课时间在不在教室里,我就能决策你是不是在偷懒;你的排名是不是前十我就能决策要不要给你发奖学金等;由此可以看出我和你见面不是我对你管理的必要条件。
见面的本质是想拿到对方的相关数据再根据数据进行管理;
如果不需要见面,如何得到数据的??
正是因为如此,所以在校长和学生之间,在老板和员工之间要增加一层。我们的数据是由这一层获取的;我们的数据就是由辅导员这个中间层对我们的数据进行获取后输入教务系统进行管理的。
由中间层获取;
由此可见操作系统想管理所有的硬件并不需要和硬件打交道,操作系统想要管理硬件是基于数据进行管理的,而数据是由驱动程序这个中间层来获取的。所以操作系统这个管理者就是要求驱动系统去获取底层硬件的数据进行管理的。
在于此同时,我们的数据也不是随便乱拿的,就像校长不可能让辅导员去拿今天学生穿了什么颜色的衣服的数据。这些数据在管理体系中没有任何意义,所以校长必须要告诉辅导员要去拿学生的什么数据。
校长1.0:
给了辅导员一个 Excel 表格,要辅导员把学生信息填入表格;
校长的管理工作就从管理学生变成了管理这批数据了。就比如:有一个什么竞赛,校长就会对照着表格把符合竞赛水准的学生让辅导员去通知让其去参加竞赛、如果校长看到一个成绩十分差劲的学生,就可能会让辅导员去通知学生被开除了,让其离开,与此同时校长会把其数据在 Excel 表格上删除,这样在学校中也不会有这个学生,在数据中校长也不会对这个学生进行管理。如果说此时又来了 100 个学生,校长又会让辅导员把他们的信息录入 Excel 表格;
校长管理学生 -> 对 Excel 表格的数据的管理;
校长每天起床的第一件事情就是遍历一遍 Excel 表格,如果就几百个学生还好,但是万一有成千上万个学生怎么办呢,难道校长不干别的事情了嘛?
我们的校长一般找学生都比较有目的性,比如找成绩前几的,找班长、找成绩倒数的等。本质不就是数据的增删查改!!
校长2.0(顶级程序员!):
在管理学生的时候能不能不要用Execl表格而是使用计算机进行管理呢?
然后校长惊奇地发现在 Excel 表格中,一行信息不就是一个学生的属性嘛,我们在计算机中应该用什么方法把学生的不同的信息整合在一起呢?假如校长只会使用 C 语言(校长是操作系统,操作系统是用C语言写的);答案是 struct(结构体);我们把一行的学生信息可以通过 struct stu 描述起来,这个类就相当于 Excel 表格上的一行的属性集;我们就可以用同一个结构体定义几万个对象,每个对象里保存的就是对应学生的基本信息;从 Excel 上的几万行表格到 C 语言中的几万个变量,只是名字不同;但是这一个个学生变量相互之间都是独立的啊。
怎么进行增删查改呢?这个时候校长灵机一动在类中增加了 next 指针,以后新产生了一个学生就对应新增一个节点,相互之间用 next 指针联系起来,校长 2.0 手上就有了一份学生链表,我们现在如果想找到一个需要对应属性的学生就转化成了一个在对应链表中找到符合需要的最大值问题;我们把日常的校长的管理学生的工作 -> 对链表的增删查改。
- 所谓的管理就是先描述,再组织的过程!!
操作系统对硬件的管理就是在其内部先描述、再组织,把网卡、磁盘等硬件定义一个类,记录它们的属性后,再对其进行组织管理;
不管是任何语言都有相应的类和 STL,本质上是因为类解决的是先描述的问题,而 STL 本质上是数据结构,解决的是再组织的问题。先描述、再组织是对任何 “ 管理 ” 场景进行建模。
2.5、系统调用和库函数的概念
- 在开发的角度,操作系统对外会表现为一个整体,但是会把部分的接口展现出来,供上层开发者使用,这部分由操作系统提供的接口,叫做系统调用;
- 系统调用在使用上,功能比较基础,对用户的要求相对也比较高,所以,有心的开发者会对部分的系统调用进行适度的封装,形成库。有了库,就很有利于更上层的用户开发或者开发者进行二次开发;
操作系统:
当我们有了操作系统这款软件后,它可以帮助我们把硬件软件管理好,就能够对上提供一个良好稳定的环境给用户,给用户提供管理服务。虽然如此,但是操作系统不相信任何用户或者人。例如:我们使用 printf 相当于把我们输入的东西放到显示器上,scanf 相当于我们把键盘数据读取到软件程序里,这些操作势必要有操作系统参与,所以操作系统要给我们提供访问硬件的能力,就叫做服务;这就十分的矛盾了,一个东西要给我们提供服务,但是却不相信我们,是如何做到的呢??
在现实生活中就有具体的例子,就比如说银行系统,银行要给我们提供很多服务,比如存钱、取钱、买理财产品等。但是实际上银行不相信我们任何人,它不会让我们进入银行的后台,也不会让我们进入银库;为了拦住我们,就给我们提供了一个巨大的窗口。银行不允许我们进入其内部、而是给我们提供了一个一个小的窗口进行访问。给我们提供服务。
操作系统也是如此,它把自己封装起来,不给用户使用,但是给我们提供叫系统调用的窗口给我们进行服务。系统调用本质上是操作系统给我们封装的函数调用,如 fork、waitpid、socket。
库函数:
在我们的银行中如果只有窗口,那么一些老年人来可能会不知道怎么操作,这个时候就有了大堂经理来指导和帮助,我们的操作系统也是如此,我们对系统调用进行封装形成不同的库和外壳,这就是库函数的由来。
关系:
库函数和系统调用是上下层的关系;
系统调用的本质:
用户和操作系统之间进行某种数据交互!!
总结
本章节结束后,大家应该对操作系统的职责有所了解。在之后的章节,我们会来一层一层的拨开操作系统神秘的面纱,大家下一章节再见。
🎇坚持到这里已经很厉害啦,辛苦啦🎇 ʕ • ᴥ • ʔ づ♡ど