乐趣区

关于操作系统:啃碎操作系统一操作系统概念

前言

最近在看 《古代操作系统》 这本书,想写几篇文章记录一下。

注释

什么是操作系统?

古代计算机系统由一个或多个处理器、主存、打印机、键盘、鼠标、显示器、网络接口以及各种输出 / 输出设备形成。

一般而言,古代计算机是一个简单的零碎。如果每位利用程序员都不得不把握零碎的所有细节,那就不可能再编写代码了。所以,计算机装置了一层软件,称为操作系统,它的工作是为用户程序提供一个更好、更简略、更清晰的计算机模型,并治理方才提到的所有设施。

这是一个操作系统的简化图,最上面的是硬件,硬件包含芯片、电路板、磁盘、键盘、显示器等咱们下面提到的设施,在硬件之上是软件。大部分计算机有两种运行模式:内核态 用户态 ,软件中最根底的局部是 操作系统 ,它运行在 内核态 中。操作系统具备硬件的拜访权,能够执行机器可能运行的任何指令。软件的其余部分运行在 用户态 下。

计算机硬件介绍

操作系统与运行操作系统的内核硬件关系密切。操作系统扩大了计算机指令集并治理计算机的资源。因而,操作系统因而必须足够理解硬件的运行,这里咱们先简要介绍一下古代计算机中的计算机硬件。

从概念上来看,一台简略的个人电脑能够被形象为下面这种类似的模型,CPU、内存、I/O 设施都和总线串联起来并通过总线与其余设施进行通信。

CPU

CPU 是计算机的大脑,它次要和内存进行交互,从内存中提取指令并执行它。一个 CPU 的执行周期是从内存中提取第一条指令、解码并决定它的类型和操作数,执行,而后再提取、解码执行后续的指令。反复该循环直到程序运行结束。

因为拜访内存获取执行或数据要比执行指令破费的工夫长,因而所有的 CPU 外部都会蕴含一些 寄存器 来保留要害变量和长期后果。因而,在指令集中通常会有一些指令用于把关键字从内存中加载到寄存器中,以及把关键字从寄存器存入到内存中。还有一些其余的指令会把来自寄存器和内存的操作数进行组合,例如 add 操作就会把两个操作数相加并把后果保留到内存中。

除了用于保留变量和长期后果的通用寄存器外,大多数计算机还具备几个非凡的寄存器,这些寄存器对于程序员是可见的。其中之一就是 程序计数器(program counter),程序计数器会批示下一条须要从内存提取指令的地址。提取指令后,程序计数器将更新为下一条须要提取的地址。

内存

计算机中第二个次要的组件就是内存。现实状况下,内存应该十分疾速(比执行一条指令要快,从而不会拖慢 CPU 执行效率),而且足够大且便宜,然而目前的技术手段无奈满足三者的需要。于是采纳了不同的解决形式,存储器零碎采纳一种分档次的构造:

顶层的存储器速度最高,然而容量最小,老本十分高,层级构造越向下,其拜访效率越慢,容量越大,然而造价也就越便宜。

寄存器

存储器的顶层是 CPU 中的 寄存器,它们用和 CPU 一样的资料制成,所以和 CPU 一样快。程序必须在软件中自行治理这些寄存器(即决定如何应用它们)

高速缓存

位于寄存器上面的是 高速缓存 。当应用程序须要从内存中读取关键词的时候,高速缓存的硬件会查看所须要的高速缓存行是否在高速缓存中。如果在的话,那么这就是 高速缓存命中(cache hit)。高速缓存满足了该申请,并且没有通过总线将内存申请发送到主内存。高速缓存命中通常须要破费两个时钟周期。缓存未命中须要从内存中提取,这会耗费大量的工夫。高速缓存行会限度容量的大小因为它的造价十分低廉。

主存

在下面的层次结构中再下一层是 主存,这是内存零碎的主力军,主存通常叫做 RAM(Random Access Memory)。所有不能再高速缓存中失去满足的内存拜访申请都会转往主存中。

除了主存之外,许多计算机还具备大量的非易失性随机存取存储器。它们与 RAM 不同,在电源断电后,非易失性随机拜访存储器并不会失落内容。ROM(Read Only Memory) 中的内容一旦存储后就不会再被批改。它十分快而且便宜。

磁盘

下一个档次是 磁盘(硬盘),磁盘同 RAM 相比,每个二进制位的成本低了两个数量级,而且常常也有两个数量级大的容量。磁盘惟一的问题是随机拜访数据工夫大概慢了三个数量级。

I/O 设施

CPU 和存储器不是操作系统须要治理的全副,I/O 设施也与操作系统关系密切。能够参考下面这个图片,I/O 设施个别包含两个局部:设施控制器和设施自身。控制器自身是一块芯片或者一组芯片,它可能管制物理设施。它可能接管操作系统的指令,例如,从设施中读取数据并实现数据的解决。

在许多状况下,理论管制设施的过程是非常复杂而且存在诸多细节。因而控制器的工作就是为操作系统提供一个更简略(但依然非常复杂)的接口。也就是屏蔽物理细节。任何简单的货色都能够加一层代理来解决,这是计算机或者人类社会很普世的一个解决方案。

总线

总线(Bus)是计算机各种性能部件之间传送信息的公共通信支线,它是由导线组成的传输线束,依照计算机所传输的信息品种,计算机的总线能够划分为数据总线、地址总线和管制总线,别离用来传输数据、数据地址和管制信号。总线是一种内部结构,它是 cpu、内存、输出、输出设备传递信息的专用通道,主机的各个部件通过总线相连接,外部设备通过相应的接口电路再与总线相连接,从而造成了计算机硬件零碎。

计算机启动过程

那么有了下面一些硬件再加上操作系统的反对,咱们的计算机就能够开始工作了,那么计算机的启动过程是怎么的呢?上面只是一个简要版的启动过程:

在每台计算机上有一块双亲板,也就是母板,母板也就是主板,它是计算机最根本也就是最重要的部件之一。主板个别为矩形电路板,下面装置了组成计算机的次要电路系统,个别有 BIOS 芯片、I/O 管制芯片、键盘和面板管制开关接口、指示灯插接件、裁减插槽、主板及插卡的直流电源供电接插件等元件。

在母板上有一个称为 根本输入输出零碎 (Basic Input Output System, BIOS) 的程序。在 BIOS 内有底层 I/O 软件,包含读键盘、写屏幕、磁盘 I /O 以及其余过程。现在,它被保留在闪存中,它是非易失性的,然而当 BIOS 中发现错误时,能够由操作系统进行更新。

在计算机 启动 (booted) 时,BIOS 开启,它会首先查看所装置的 RAM 的数量,键盘和其余根底设施是否已装置并且失常响应。接着,它开始扫描 PCIe 和 PCI 总线并找出连在下面的所有设施。即插即用的设施也会被记录下来。如果现有的设施和零碎上一次启动时的设施不同,则新的设施将被重新配置。

最初,BIOS 通过尝试存储在 CMOS 存储器中的设施清单尝试启动设施。

操作系统概念

大部分操作系统提供了特定的根底概念和形象,例如 过程、地址空间、文件 等,它们是须要了解的核心内容。

过程

操作系统一个很要害的概念就是 过程 (Process)。过程的实质就是操作系统执行的一个程序。与每个过程相干的是 地址空间 (address space),这是从某个最小值的存储地位(通常是零) 到某个最大值的存储地位的列表。在这个地址空间中,过程能够进行读写操作。地址空间中寄存有可执行程序,程序所须要的数据和它的栈。与每个过程相干的还有资源集,通常包含 寄存器 (registers)(寄存器个别包含 程序计数器 (program counter)堆栈指针(stack pointer))、关上文件的清单、突发的报警、无关的过程清单和其余须要执行程序的信息。你能够把过程看作是包容运行一个程序所有信息的一个容器。

对过程建设一种直观感觉的形式是思考建设一种多程序的零碎。思考上面这种状况:用户启动一个视频编辑程序,批示它依照某种格局转换视频,而后再去浏览网页。同时,一个查看电子邮件的后盾过程被唤醒并开始运行,这样,咱们目前就会有三个流动过程:视频编辑器、Web 浏览器和电子邮件接管程序。操作系统周期性的挂起一个过程而后启动运行另一个过程,这可能是因为过来一两秒钟程序用完了 CPU 调配的工夫片,而 CPU 转而运行另外的程序。

像这样临时中断过程后,下次应用程序在此启动时,必须要复原到与中断时刻雷同的状态 ,这在咱们用户看起来是司空见惯的事件,然而操作系统外部却做了微小的事件。这就像和足球比赛一样,一场完满精彩的较量是能够疏忽裁判的存在的。这也意味着在挂起时该过程的所有信息都要被保留下来。例如,过程可能关上了多个文件进行读取。与每个文件相关联的是提供以后地位的指针(即下一个须要读取的字节或记录的编号)。当过程被挂起时,必须要保留这些指针,以便在重新启动过程后执行的 read 调用将可能正确的读取数据。在许多操作系统中,与一个过程无关的所有信息,除了该过程本身地址空间的内容以外,均寄存在操作系统的一张表中,称为 过程表(process table),过程表是数组或者链表构造,以后存在每个过程都要占据其中的一项。

地址空间

每台计算机都有一些主存用来保留正在执行的程序。在一个非常简单的操作系统中,仅仅有一个利用程序运行在内存中。为了运行第二个应用程序,须要把第一个应用程序移除能力把第二个程序装入内存。

简单一些的操作系统会容许多个应用程序同时装入内存中运行。为了避免应用程序之间互相烦扰(包含操作系统),须要有某种爱护机制。尽管此机制是在硬件中实现,但却是由操作系统管制的。

通常,每个过程有一些能够应用的地址汇合,典型值从 0 开始直到某个最大值。一个过程可领有的最大地址空间小于主存。在这种状况下,即便过程用完其地址空间,内存也会有足够的内存运行该过程。

然而,在许多 32 位或 64 位地址的计算机中,别离有 2^32 或 2^64 字节的地址空间。如果一个过程有比计算机领有的主存还大的地址空间,而且该过程心愿应用全副的内存,那该怎么解决?在晚期的计算机中是无奈解决的。然而当初有了一种 虚拟内存 的技术,操作系统能够把局部地址空间装入主存,局部留在磁盘上,并且在须要时来回替换它们

文件

简直所有操作系统都反对的另一个要害概念就是 文件系统 。如前所述,操作系统的一项次要性能是屏蔽磁盘和其余 I/O 设施的细节个性,给程序员提供一个良好、清晰的独立于设施的形象文件模型。 创立文件、删除文件、读文件和写文件 都须要零碎调用。在文件能够读取之前,必须先在磁盘上定位和关上文件,在文件读过之后应该敞开该文件,无关的零碎调用则用于实现这类操作。

在读写文件之前,首先须要关上文件,查看其拜访权限。若权限许可,零碎将返回一个小整数,称作 文件描述符(file descriptor),供后续操作应用。若禁止拜访,零碎则返回一个错误码。

在 UNIX 中,另一个重要的概念是 非凡文件(special file)。提供非凡文件是为了使 I/O 设施看起来像文件个别。这样,就像应用零碎调用读写文件一样,I/O 设施也能够通过同样的零碎调用进行读写。依照常规,非凡文件保留在 /dev 目录中。例如,/devv/lp 是打印机。

还有一种与过程和文件相干的个性是管道,管道(pipe) 是一种虚文件,他能够连贯两个过程:

如果 A 和 B 心愿通过管道对话,他们必须提前设置管道。当过程 A 绝对过程 B 发送数据时,它把数据写到管道上,相当于管道就是输入文件。这样,在 UNIX 中两个过程之间的通信就十分相似于一般文件的读写了。

输入输出

所有的计算机都有用来获取输出和产生输入的物理设施。毕竟,如果用户不能通知计算机该做什么,且在计算机实现了所要求的工作之后竟不能失去后果,那么计算机还有什么用途呢?有各种类型的输入输出设施,包含键盘、显示器等等,对这些设施的治理全靠操作系统。

爱护

计算机中含有大量的信息,用户心愿可能对这些信息中有用而且重要的信息加以爱护,这些信息包含电子邮件、商业打算等,治理这些信息的安全性齐全依附操作系统来保障。例如,文件提供受权用户拜访。

比方 UNIX 操作系统,UNIX 操作系统通过对每个文件赋予一个 9 位二进制爱护代码,对 UNIX 中的文件实现爱护。该爱护代码有三个位子段,一个用于所有者,一个用于与所有者同组(用户被系统管理员划分成组)的其余成员,一个用于其他人。每个字段中有一位用于读拜访,一位用于写访问,一位用于执行拜访。这些位就是驰名的 rwx 位。例如,爱护代码 rwxr-x--x 的含意是所有者能够读、写或执行该文件,其余的组成员能够读或执行(但不能写)此文件、而其他人能够执行(但不能读和写)该文件。

shell

操作系统是执行零碎调用的代码。编辑器、编译器、汇编程序、链接程序、应用程序以及命令解释符等,只管十分重要,十分有用,然而它们的确不是操作系统的组成部分。上面咱们着重介绍一下 UNIX 下的命令提示符,也就是 shell,shell 尽管有用,但它也不是操作系统的一部分,然而它却能很好的阐明操作系统很多个性,上面咱们就来探讨一下。

shell 有许多种,例如 sh、csh、ksh 以及 bash等,它们都反对上面这些性能,最早起的 shell 能够追溯到 sh

用户登录时,会同时启动一个 shell,它以终端作为规范输出和规范输入。首先显示 提示符 (prompt),它可能是一个 美元符号($),提醒用户 shell 正在期待接管命令,如果用户输出

date 

shell 会创立一个子过程,并运行 date 做为子过程。在该子过程运行期间,shell 将期待它完结。在子过程实现时,shell 会显示提示符并期待下一行输出。

用户能够将规范输入重定向到一个文件中,例如

date > file 

同样的,也能够将规范输出作为重定向

sort <file1> file2 

这会调用 sort 程序来接管 file1 的内容并把后果输入到 file2。

能够将一个应用程序的输入通过管道作为另一个程序的输出,因而有

cat file1 file2 file3 | sort > /dev/lp 

这会调用 cat 应用程序来合并三个文件,将其后果输送到 sort 程序中并依照字典进行排序。sort 应用程序又被重定向到 /dev/lp,显然这是一个打印操作。

零碎调用

少数古代操作系统都有性能雷同然而细节不同的零碎调用,引发操作系统的调用依赖于计算机本身的机制,而且必须用汇编代码表白。任何单核 CPU 计算机一次执行执行一条指令 。如果一个过程在用户态下运行用户程序,例如从文件中读取数据。那么如果想要把控制权交给操作系统管制,那么必须执行一个异样指令或者零碎调用指令。操作系统紧接着须要参数查看找出所须要的调用过程,而后执行零碎调用,把控制权移交给零碎调用上面的指令。大抵来说,零碎调用就像是执行了一个非凡的过程调用,然而只有 零碎调用可能进入内核态,而过程调用则不能进入内核态

为了可能理解具体的调用过程,上面咱们以 read 办法为例来看一下调用过程。像下面提到的那样,会有三个参数,第一个参数是指定文件、第二个是指向缓冲区、第三个参数是给定须要读取的字节数。就像简直所有零碎调用一样,它通过应用与零碎调用雷同的名称来调用一个函数库,从而从 C 程序中调用:read。

count = read(fd,buffer,nbytes); 

零碎调用在 count 中返回理论读出的字节数。这个值通常与 nbytes 雷同,但也可能更小。比方在读过程中遇到了文件尾的状况。

如果零碎调用不能执行,不论是因为有效的参数还是磁盘谬误,count 的值都会被置成 -1,而后在全局变量 errno 中放入谬误信号。程序应该进场查看零碎调用的后果以理解是否出错。

上面,咱们会列出一些罕用的零碎调用,POSIX 零碎调用大略有 100 多个,它们之中最重要的一些调用见下表:

过程治理

调用 阐明
pid = fork() 创立与父过程雷同的子过程
pid = waitpid(pid, &statloc,options) 期待一个子过程终止
s = execve(name,argv,environp) 替换一个过程的外围映像
exit(status) 终止过程执行并返回状态

文件治理

调用 阐明
fd = open(file, how,…) 关上一个文件应用读、写
s = close(fd) 敞开一个关上的文件
n = read(fd,buffer,nbytes) 把数据从一个文件读到缓冲区中
n = write(fd,buffer,nbytes) 把数据从缓冲区写到一个文件中
position = iseek(fd,offset,whence) 挪动文件指针
s = stat(name,&buf) 获得文件状态信息

目录和文件系统治理

调用 阐明
s = mkdir(nname,mode) 创立一个新目录
s = rmdir(name) 删去一个空目录
s = link(name1,name2) 创立一个新目录项 name2, 并指向 name1
s = unlink(name) 删去一个目录项
s = mount(special,name,flag) 装置一个文件系统
s = umount(special) 卸载一个文件系统

其它

调用 阐明
s = chdir(dirname) 扭转工作目录
s = chmod(name,mode) 批改一个文件的爱护位
s = kill(pid, signal) 发送信号给过程
seconds = time(&seconds) 获取从 1970 年 1 月 1 日至今的工夫

下面的零碎调用参数中有一些公共局部,例如 pid 零碎过程 id,fd 是文件描述符,n 是字节数,position 是在文件中的偏移量、seconds 是流逝工夫。

总结

好了,无关操作系统相干概念临时介绍到这里,如果须要电子版的《古代操作系统》能够私信我。

参考

《古代操作系统》

退出移动版