我对计算机系统的理解

计算机系统的组成

一个计算机系统是由软件与硬件组成的,就硬件来讲,当咱们通常去电脑城配电脑的时候,通常会购买这些基本零部件:主板,CPU,内存,磁盘,机箱,键盘鼠标,显示器。固然还有一些额外的部件,例如独立显卡或者网卡,音箱等。若是除去非必要的部件来看,其实一个计算机系统主要由下面这些重要的部件组成:
CPU,存储器(内存),磁盘,IO设备(键鼠,显示器),以及链接这些器件总线,只不过咱们的成品电脑是用一块电路板将这些部件链接在了一块儿。固然随着电脑系统愈来愈强大,可能除了上述部件以外,还多了不少其余的部件,例如我的PC的主板上可能还有南桥,北桥等等一系列的额外的芯片。可是咱们这里讨论的是组成一个计算机系统最基本的部件,其余的部分,为了简化说明,暂时省略。

CPU:是一个计算机最核心的部分,计算机的全部运算,程序的全部指令的执行是经过CPU来进行的,CPU是计算机的大脑。

存储器:CPU所执行的指令,计算的中间结果,产生的数据都须要经过某种方式进行保存,方便CPU读取和存入,这就是存储器的功能。

磁盘:提供永久保存数据的办法。

IO:也便是链接在计算机上的输入输出设备,通常最多见的就是鼠标,键盘和显示器了,固然还有其余的一些输入输出设备,例如打印机,USB外接设备等。IO设备主要提供给人们与计算机进行交互的时候使用。

总线:全部这些部件之间经过总线进行链接,有些设备共享一组总线,有的设备之间有专用的总线。

计算机的软件组成:计算机除了硬件系统以外,在硬件系统之上运行着一系列的软件,最重要的固然是操做系统软件,另外还有各类驱动程序用于与特定的设备进行通讯。除此以外还有各类运行在操做系统之上的用户应用程序。node

程序是如何在计算机上运行的

程序是什么:
在计算机系统上运行着各类各样的程序,包括操做系统自己也是程序,那么程序究竟是什么呢,程序通常以文件的形式存在于磁盘上,这些文件是具备必定结构的二进制文件,这些文件被以一种特定含义的格式进行组织,例如典型的二进制的可执行文件(无论是windows仍是linux系统)以必定的结构描述,在这些描述中,该文件被分红了多个段,每一个段中的数据内容具备不一样的含义,例如数据段,代码段,符号表等等。其中代码段中的二进制数据,咱们认为就是CPU直接执行的指令。

CPU的指令是什么:
一条CPU的指令是一串不定长的二进制的位串,而当CPU读取这一个位串并执行的时候,通常是运行一个特定的功能,例如加法,减法,从内存读取一个字节到寄存器等等这样的功能,而一个CPU可以执行的全部二进制位串(也就是指令)的集合则是CPU的指令集。不一样的硬件厂商生产的CPU他们可以识别执行的二进制位串序列集(CPU指令)多是不同的。而一样的功能,例如加法功能,不一样的CPU须要执行的二进制位串多是不同的。例如咱们常见的PC机器的x86架构的CPU基本上是兼容的,目前市面上主流的PC端的CPU由Intel和AMD生产,这两个厂家生产的CPU的指令基本上是兼容的,可是也可能各自有一些特定的指令是对方没有的。另外的例如Arm或者mips的CPU的指令集则与x86体系是不一样的,而前者多用于嵌入式系统。

CPU的硬件自己能够理解为是一系列的电路,该电路实现必定的功能,该电路中又分红了不少的功能单元,例如在现代CPU的设计中,一条计算机指令在执行的时候,会通过:取指、译码、执行、访存,写回,更新PC等阶段,而现代CPU被设计成以流水线的方式执行指令。如前所述,一条指令是若干个二进制bit位的位串,在取指阶段CPU根据程序计数器(PC)中的地址取出当前须要执行的指令。接着对该指令译码,所谓译码则是解析该指令,通常一条指令被分红了多个部分,每一个部分表明不一样的含义,一条IA32的指令是由1到15个字节组成,操做数较少的指令所须要的字节数少,那些不太经常使用的或者操做数较多的指令所须要的字节数较多。在执行阶段由CPU的算术/逻辑单元执行指令。访存阶段将数据写入存储器或者从存储器中读出数据。写回阶段将结果写到寄存器中。更新PC阶段则将PC计数器设置成下一条指令的地址。

程序的编译与连接过程:
一个程序的生成流程能够大体描述为:程序文本文件、编译成汇编文件(.s)、编译成二进制文件(.obj)、连接成最终的可执行文件。CPU只能识别并执行他的指令集中的位串,因此咱们必须将程序员能够识别的文本文件的程序代码转换成CPU可以执行的一系列的指令,这个转换过程就是编译过程。而连接是一个很是复杂的过程,其中包括静态连接和动态连接,连接的过程是将全部模块中使用的符号替换成实际使用的内存地址的过程(而其实现代操做系统中程序访问的内存地址并非实际的物理地址,而是虚拟地址)。静态连接是在编译阶段由连接器完成连接过程直接生成可执行程序的过程。动态连接是在程序执行阶段动态将程序中的符号替换成为实际的内存地址的过程,例如咱们的C程序里面通常调用了C的标准库函数,而C的标准库函数是在其动态连接库libc.so中的,在咱们的程序执行的时候,会将libc.so所在的内存地址映射到程序的虚拟地址空间,并修改程序中全部访问libc.so中的符号为正确的访问地址的过程。这个过程就是动态连接。

程序的执行过程:
一个程序要想被执行,首先要将其文件内容加载到内存中,而后CPU从程序的代码段的入口点的第一条指令开始执行,后面的全部执行过程都是按照程序中的指令进行的,一直到程序结束为止。这一整个过程实际上并无这几句话描述的这么简单,首先程序被从磁盘读取到内存这一过程,可能涉及到磁盘的IO中断,DMA的拷贝,虚拟内存等,当程序被加载进内存以后,若是程序使用了动态链接库,例如最简单的C程序也可能连接了C的标准库,因此还须要加载动态库(通常是经过内存映射的方式),将动态库加载进内存,并将其映射到程序的虚拟地址空间中。最后通过一些初始化以后(初始化寄存器,库的初始化等),开始从程序的入口处的指令执行。linux

操做系统是什么

什么是操做系统呢,通常状况下咱们提到操做系统就认为高深莫测,深不见底。其实操做系统的做用能够从这么几个方面来理解,首先操做系统的一个很是重要的功能便是提供用户接口,也就是说当人们要使用计算机的时候,必须经过一种方式来控制计算机,那么操做系统提供了这样的方式来令人们能够控制计算机,例如命令行的或者是UI的方式,这种接口咱们能够理解为使用计算机的入口。另一种接口用于扩展计算机的功能,例如程序员编写程序的时候就会使用操做系统提供的系统接口,这种接口是更底层的概念。

其实咱们说的用户接口不必定是操做系统的一部分,例如典型的linux类型的操做系统,其桌面环境是能够不用的,或者是能够随意替换的,其shell命令行环境也能够本身替换,在linux中有多种可使用的shell,而惟一不能改变的是linux内核,这么说来linux的桌面环境以及shell命令行环境好像并不属于操做系统,可是倒是计算机中不可缺乏的。而在windows操做系统中,特别是windows xp 和windows NT 中其GUI界面是夹在内核中的,这样一来其又是操做系统的一部分了。因此其实从功能上来讲现代操做系统的软件界限实际上是愈来愈模糊了。

操做系统除了提供用户接口以外,仍是计算机系统的管理者,负责管理各类软硬件资源,制定计算机世界的规则,例如操做系统管理CPU,调度各类进程,线程来使CPU执行指令。管理内存,提供进程访问内存的规则,还有磁盘,外设等设备的管理。若是没有这些管理,咱们的程序能够乱执行,谁先执行,谁后执行? 执行多久?内存区域能够乱写,我能够破坏你的内存,你能够破坏个人内存。就像在道路上没有警察去约束,那交通确定是一片混乱。

什么是驱动程序呢,驱动程序严格的来讲并非一个单独的程序,也不是一个独立运行的进程,实际上咱们能够理解驱动程序是一个程序片断,或者是一个符合必定约定提供约定接口的程序库,操做系统调用该库中提供的接口,去操做特定的硬件。该库实现了对特定硬件的操做,并提供一个对外的接口供操做系统调用。例如对于磁盘来讲,生产磁盘的硬件厂商必定会提供从磁盘读取或者写入磁盘数据的办法,该办法(多是一系列的底层C接口)可能很复杂,须要不少个步骤,寻址,寻道等。并且不一样的磁盘厂商提供的底层接口并不必定相同,那么磁盘驱动程序封装了这些底层的操做磁盘的功能,并对外提供统一的操做接口(该接口规范是操做系统规定的,这样操做系统才能统一调用)。那么符合规定接口的该软件库咱们能够认为就是驱动,有的驱动程序是随操做系统启动的时候进行加载的,而有的能够直接即时安装进行动态加载,这有赖于动态连接库的运行时加载功能。程序员

进程与线程

什么是进程呢,咱们的程序其实是一个二进制文件存放在磁盘中,当将程序载入到内存中,并从第一条指令开始执行,一直到最后一条指令结束该程序文件中的指令再也不被CPU执行,那么该程序的这一次的运行过程,咱们能够理解为是一个进程。也就是说一个进程是一个二进制的程序中的指令从第一条指令被CPU执行,一直到最后一条指令被CPU执行的这整个过程。进程是一个磁盘中的程序运行的实例。

一个程序文件是一个具备必定结构的二进制文件,通常状况下不一样的操做系统的二进制文件的结构是不一样的,可是其大致概念是类似的,例如linux和windows程序文件都包含有代码段,数据段,符号表等等区域。程序文件中除了代码段中的二进制数据是CPU真正要执行的指令之外,其余的段要么是在CPU执行过程当中须要使用到的内存信息(例如变量),要么是编译器调试的时候须要用到的辅助信息(例如符号表)。

在操做系统中有一些信息是与一个运行的程序,也就是进程相关联的,通常咱们称之为PCB(进程控制块),该信息中描述了进程在运行过程与该进程关联的信息,例如进程的ID,程序计数器,堆栈等等。

一般每个进程有一个地址空间和一个控制线程(主线程),固然一个进程中能够有多个控制线程,这些线程就像分离的进程同样,只不过他们共享同一个进程的地址空间以及其余资源。在内存中也有一个信息结构来记录与每一个线程关联的信息,例如程序计数器,堆栈信息等。

进程是资源分配的最小单位,线程是CPU调度的最小单位。算法

单线程与多线程程序、并发

一个程序究竟是单线程结构好仍是多线程好呢?从CPU的角度上来看,若是是单核CPU在任什么时候刻,只能运行一个进程,也就是说只能调度一个线程(若是是单线程的程序则运行进程的时候实际上调度的是该进程的主线程),单核CPU的多任务并发其实是伪并发,任什么时候刻只有一个进程处于运行中,只不过CPU的运行很快,多个进程能够轮番获得CPU,看起来好像是同时运行的同样。线程是CPU调度的最小单位,任什么时候刻只有一个线程得到CPU运行,因此理论上多个线程运行的时候多了线程上下文切换的开销,应该比单线程的进程效率低。可是因为复杂程序的业务逻辑,单线程程序中若是有阻塞的逻辑,则反而由于阻塞,该线程被操做系统切换出去,不能获得CPU,而下降了程序获得CPU的时间,另外单线程程序的设计每每比较复杂,由程序设计带来的复杂性可能会抵消多线程上下文切换的损失。因此通常状况下当程序中有比较耗时的操做时,单线程程序是不合适的,应该用多线程比较好。若是是CPU密集型的程序,加上良好的程序设计,则使用单线程的结构效率比较高(单线程的程序通常使用状态机来驱动程序的运行)。而即便多线程的程序有本身的优势,也并非线程越多越好,当线程很是多的时候线程上下文切换的开销就比较可观了。现代计算机通常都拥有多核CPU,从这点上来说多线程的程序更能取得比较高的CPU利用率。shell

存储管理

存储器是计算机系统中的重要组成部分,一个程序要执行,必须先从磁盘拷贝到内存上,而后从内存中读取计算机指令进行执行。而计算机存储的使用历史也是伴随着计算机以及操做系统的发展变化的。

最开始的操做系统是单任务的操做系统,某一时刻只有一个进程在执行,也没有线程的概念。因此程序中使用的地址都是实际的物理地址,而该物理地址是编译器在编译阶段分配的。程序在运行以前被载入内存中而后被执行。

随着用户不知足于只运行一个程序,多个程序开始被同时执行,那么此时程序中的地址就不可能使用实际的物理地址了,由于要保证两个程序同时执行互相不产生干扰的话,他们就不该该同时访问相同的物理地址,而若是此时程序中使用的地址仍是实际的物理地址而且须要保证程序访问的地址空间不会重叠,在编译阶段编译器几乎不可能实现。编译器可能的实现方式是使用相对地址,而程序只须要在运行阶段知道一个基地址,程序中的其余地址则经过基地址加上偏移地址(也就是相对地址由编译阶段填到程序中)的方式来实现。固然也会有一个寄存器去记录程序访问内存的最大边界,以防止程序访问越界。这种方式解决了多个程序同时运行的内存分配问题,使用统一的方式来分配内存,也下降了编译器编译的复杂度。

若是内存空间无限大,使用基地址加上偏移地址的方式便可解决内存的分配问题。而实际上虽然即便如今内存空间愈来愈大,可是随着程序愈来愈大,用户要求同时运行的程序愈来愈多,要想在程序运行以前将全部程序载入到内存,以如今的内存空间恐怕是办不到的,特别是有的程序动则以G为单位。为了适应这样的需求,出现了内存交换的技术,其实现过程是这样的,例若有3个程序须要运行,先载入程序A运行,再载入程序B运行,此时再载入C运行,然而剩余的内存空间不够载入C程序,此时能够选择将B程序运行的全部内存映像交换到磁盘空间保存,这样B程序占用的内存空间被释放,而后载入C程序运行,如此反复。这种方式就是内存交换技术。可是即便采用内存交换技术,也只能解决一部分问题,另外即便现代磁盘的传输速度愈来愈快,可是频繁的内存交换,仍然会大大影响程序的性能,特别是当运行的程序很大的时候,例如将1G的程序交换到磁盘上,即便SATA磁盘传输的峰值是100MB/s也仍然须要10秒才能完成交换操做,而将该程序载入到内存中从新运行也须要一样的时间。

现代操做系统采起另一种方式来作这样的操做,即将程序分割成不少的小块,每一小块的大小或是4K,或是8K,16K,32K等,每次载入程序的时候以块为单位载入。这些分块操做所有由计算机完成,不须要程序员干预,这种方式被称为虚拟内存。每一个程序有本身的地址空间,这个空间被分割成多个块,每一个块称为一个页或者页面,每一页有连续的地址范围。这些页被映射到物理内存,而并不要求全部的页都在内存中才能运行程序,当程序引用到的地址在实际的物理内存中有对应的映射的时候,由硬件来翻译该地址为实际的物理地址,若是没有对应的映射,则会引起一个缺页中断,由操做系统负责将缺失的部分载入到物理内存并从新执行失败的指令。

程序使用的地址空间叫虚拟地址空间,虚拟地址空间中的地址都是虚拟地址,其地址范围能够从0到最大的物理内存地址,例如物理内存是4G,那么程序的虚拟地址空间是0-4G,每一个程序都是这样。那么若是同时运行多个程序会怎样呢,这样两个程序均可以访问到最大的4G内存,若是他们访问的是同一个地址会怎么样?在实际运行过程当中,虚拟地址会被一个叫作MMU(内存管理单元)的设施翻译成为实际的物理地址,也就是说每个程序使用的虚拟地址都会被映射到实际的物理地址,而两个程序中相同虚拟地址会被映射到不一样的物理地址,这样就不存在访问冲突的问题了。程序的虚拟地址空间是相同的,这给编译器的编写带来了极大的方便,生成的程序代码使用统一的地址空间模型,地址的翻译工做交给了MMU与操做系统。

以上其实是现代计算机采用的内存运行模型,实际上这是最基本的原理,还有一些其余的细节,例如程序的虚拟地址空间被分红多个页,每一个页会映射到实际的物理地址页,而物理地址页咱们称为页框,页与页框的大小通常是相同的,而页与页框的映射关系表则称为页表。关于页到页框的解析也是一个复杂过程,在页表项中的各类二进制位用于解析页到页框的映射。

当发生缺页中断的时候,由操做系统负责载入缺失的页面到物理内存中,固然若是内存够的话是没有任何问题的,若是在内存不够的状况下,则必需要作出选择将内存中的其余页交换到磁盘中,这样腾出空间给即将加载的页,当操做系统成功加载须要的页以后,会从新修改页表中的映射关系,并执行引起缺页中断的指令,继续原来程序的执行过程。那么操做系统如何选择将哪些页面交换到磁盘以腾出内存空间呢,这种选择的策略则是页面置换算法的内容。现代操做系统有多种页面置换算法,并不会单纯的采用某一种算法,而是综合使用。例如最优页面置换,最近未使用页面置换,先进先出页面置换,时钟页面置换,最近最少使用页面置换等等。

由于有了虚拟内存的存在,能够将同一个物理内存映射到两个不一样程序的虚拟地址空间中,这样两个程序能够同时读写该块物理内存区域,这就是共享内存。一样能够将虚拟地址空间映射到一个文件,这样程序能够像操做内存同样方便的读写一个文件,这是内存映射文件。windows

文件系统

什么是文件系统呢,在说明这个概念以前,咱们先说说文件是怎么存储的,咱们以存储介质硬盘为例,硬盘的物理结构是由不少盘片组成的,每个盘片有两面,每一面由一圈一圈的同心圆组成的磁道,而将多个盘片叠在一块儿以后,全部叠在一块儿的盘片上的同一个位置的同心圆组成一个圆柱体,这个由全部盘片上相同的磁道组成圆柱称为柱面。而每个盘片上的每个磁道被分割成一些等分的圆弧,这些圆弧叫扇区。在物理上经过电磁的原理从磁盘读写数据,咱们能够认为能够将0,1这两种不一样的状态记录到磁盘的磁道上,而这些连续的0,1的状态就是计算机中的二进制位流。因此能够认为在磁道上存储的就是表示不一样状态的二进制位流数据。那么整个磁盘是由多个盘片组成的,每一个盘片上有不少磁道,如何组织这些数据呢?就必需要对全部的盘片,柱面,扇区,磁道进行标识,而且方便查找与读写。也就是说须要用一个结构或者一组规则来组织他们,这就是文件系统。

文件系统是操做系统用于明确存储设备或分区上的文件的方法和数据结构,也就是存储设备上组织文件的方法,从系统角度看,文件系统是对文件存储设备的空间进行组织和分配,负责文件存储并对存入的文件进行保护和检索的系统。具体的说,它负责为用户创建文件,存入、读出、修改、转储文件,控制文件的存取,当用户再也不使用时撤销文件等。

若是没有文件系统这样的组织规则,那么咱们看磁盘则是一连串的无心义的二进制位流数据,咱们分不清楚哪里是开始,哪里是结束,这些二进制位流信息的含义。就好像一个doc文档,咱们使用二进制编辑软件打开以后看到的就是一连串毫无心义的二进制位流同样,然而使用doc文档的结构规则来解析这些位流信息的含义,咱们能够解析出该doc文档中的文字,图片,以及格式等信息。而文件系统也起到相似的做用,文件系统自己也占用磁盘空间,是存放在磁盘上的。多数磁盘划分为一个或多个分区,每一个分区中均可以有一个独立的文件系统。磁盘的0号扇区称为主引导记录(MBR),用来引导计算机。在MBR的结尾是分区表。该表给出了每一个分区的起始和结束地址。表中的一个分区被标记为活动分区,在计算机被引导时,BIOS读入并执行MBR。MBR作的第一件事是肯定活动分区,读入它的第一个块,称为引导块,并执行之。引导块中的程序将装载该分区中的操做系统。

每个磁盘分区由引导块、超级块、空闲空间管理、i节点、根目录、其余文件和目录的顺序组成。超级块包含文件系统的全部关键参数,在计算机启动的时候或者该文件系统首次使用时,把超级块读入内存。超级块中的典型信息包括:肯定文件系统类型用的魔数、文件系统中数据块的数量以及其余重要的管理信息。

在读文件前必须先打开文件,打开文件时,操做系统利用用户给出的路径找到相应的目录项,目录项中提供了查找文件磁盘块所须要的信息。而文件的属性信息能够存放在目录项中或者存放在文件的i节点的信息中。而这些目录项以及i节点存放在物理磁盘的哪一个柱面,哪一个磁道,哪一个扇区的信息是能够在i节点信息以及从根目录根据路径层层查找的目录项信息中获得的。

光盘的存储方式与磁盘相似,只不过光盘使用的介质并非磁介质,而是其余类型的介质,因此光盘没有磁道的概念,光盘其实是经过一个螺旋状的相似于磁道的轨迹来存储数据的,在这条轨迹上记录了0,1两种不一样状态的位流数据。因为光盘的存储特性,光盘上的文件系统与磁盘使用的文件系统是有不一样的,具体能够查阅光盘相关的格式与文件系统文档,可是其思路与磁盘文件系统是相似的。网络

输入输出(IO)

操做系统管理者各类各样的链接到计算机上的输入输出设备,IO设备能够分为两类,块设备和字符设备,块设备把信息存储在固定大小的块中,每一个块有本身的地址。一般块的大小在512字节和32768字节之间。全部传输以一个或多个完整的块为单位。块设备的基本特征是每一个块都能独立于其余的块进行读写。硬盘,CD-ROM,USB盘是常见的块设备。另外一种设备是字符设备,字符设备以字符为单位发送或接受一个字符流,而不考虑任何块结构。字符设备是不可寻址的,也没有寻道操做。打印机,网络接口,鼠标,以及大多数与磁盘不一样的设备均可以看做是字符设备。

IO设备通常由机械部件和电子部件两部分组成,电子部件称做设备控制器或者适配器。在我的计算机上它常常以主板上的芯片的形式出现,或者以插入(PCI)扩展槽中的印刷电路板的形式出现。机械部件则是设备自己。

控制器与设备之间的接口是一个很低层次的接口。以磁盘设备为例,从设备中出来的是一个串行的位流,控制器的任务是把串行的位流转换为字节块,并进行必要的错误校订工做,字节块一般首先在控制器内部的一个缓冲区按位进行组装,而后进行校验证实字节块没有错误以后,将它复制到主存中。

CPU如何从设备中读取数据(例如磁盘)或写数据到设备中呢? CPU从磁盘读写数据是直接与磁盘的设备控制器(也就是磁盘适配器)进行数据交互的,每一个设备控制器中有几个寄存器用来与CPU进行通讯,经过写入这些寄存器,操做系统能够命令设备发送数据,接收数据,开启或者关闭,或者执行其余操做。经过读取这些寄存器的值,操做系统能够知道设备当前的状态。除了设备控制器中的寄存器以外,许多设备还有一个操做系统能够读写的数据缓冲区,能够供程序或者操做系统读写数据。那么操做系统要操做这些控制寄存器,就须要有一个地址来标识这些控制寄存器,有两种方式对控制寄存器进行地址编号,一种是为每一个控制寄存器分配一个IO端口号,全部IO端口造成IO端口空间,该端口空间独立于内存的地址空间,是彻底不一样的。IO端口空间受到保护使普通的用户程序不能访问,只有操做系统能够访问。CPU能够经过这些IO端口号来读写控制寄存器的内容,从而达到与设备控制器通讯的目的。另外一种是将IO端口号映射到内存的地址空间,每一个控制寄存器被分配一个内存地址,这样的系统称为内存映射IO。一般分配给控制寄存器的地址位于内存地址的顶端,而且该地址不会再分配给应用程序。在这种模式下,IO端口的地址与内存地址是一个地址空间,并非独立的。这种模式的好处是,不须要使用特定的指令去操做控制寄存器,只须要普通的访问内存的指令便可以对控制寄存器进行读写操做,就像程序中普通读写内存同样。

上面讲述了CPU如何与设备进行通讯的原理,那么读写文件的具体过程是怎么样的呢? 通常状况是这样的,在程序中咱们通常经过系统提供的read,write函数对文件进行读写,固然在读写以前通常会有一个open操做(传递一个文件路径,以及打开的方式),读写完成以后通常会有一个close操做关闭文件。当使用open操做打开一个文件的时候,最终会调用到文件系统的相关接口,而且返回的文件描述符与文件的inode节点信息在操做系统的内核中确定有对应的关联关系,此后在read或者write的时候传递进去的文件描述符,最后应该被文件系统关联到文件相关的底层结构例如inode信息,经过inode信息就能够操做该文件在磁盘上的块了(文件系统应该有查找文件的第几个字节在磁盘的哪一个块上的能力)。在write或者read的时候,CPU先通知磁盘设备控制器,设备控制器从磁盘寻道,寻址,一位一位的读取某一个块(或者是以扇区为单位),直到将整个块读入到控制器的内部缓冲区中,计算校验和,保证没有错误。而后控制器产生一个中断,等到操做系统响应的时候,CPU从设备控制器的缓冲中一个字节一个字节的读取数据,并拷贝到内存中(read的时候会指定一个buffer,也就是数据要读到的内存地址)。这种模式是IO操做模式中的一种。下面说说IO实现的三种方法。

第一种方法是程序控制IO,程序须要轮询IO设备的状态,以查看IO设备是否准备好,例如打印机,程序须要轮询打印机中的寄存器,以查看打印机是否准备好接受打印的字符,若是准备好,程序将须要打印的字符拷贝到打印机的缓冲区中,若是打印机此时开始打印一个字符,并同时设置打印机的状态为非就绪,在打印机打印该字符的过程当中,程序必须一直查询并等待打印机完成该字符的打印直到打印机完成该字符的打印过程以后,其寄存器中表示打印机状态的值被改成就绪状态,程序拷贝第二个须要打印的字符到打印机的缓冲区中。如此循环,直到全部打印完成为止。这种模式浪费了大量的CPU时间,由于打印机打印的过程是一个耗时的过程,而在CPU等待打印机打印字符的过程,将大量的CPU周期浪费在轮询打印机的状态上,这就出现了第二种方式。

第二种方式是中断驱动的IO,当打印机开始打印第一个字符的时候,CPU去作其余事情(与当前打印相关的进程被调度到阻塞状态,其余的进程或者线程得到CPU),打印机完成第一个字符的打印以后,发出一个中断,中断处理程序运行,以前被挂起的进程从新开始运行,拷贝第二个须要打印的字符给打印机,如此反复。在这种模型下,因为IO设备的操做很慢(例如打印机的打印操做),在IO设备执行操做的时候CPU没必要等在那里,而是能够作其余事情,等IO操做完成以后,以中断的方式通知,这样大大的节约了CPU的时钟周期。这种方式的缺点是每一次IO设备的读写都会产生中断,中断发生在每一个字符上。并且中断是须要花费时间的,因此这一方法将浪费必定量的CPU时间。

第三种方式是使用DMA(直接存储器存取),让DMA控制器来操做IO而不是CPU。本质上DMA是程序控制IO,只不过是由DMA控制器而不是主CPU作所有工做。其实咱们能够想象成DMA是一个特定功能的CPU,该特定功能也便是对IO设备的操做。将原来须要CPU进行IO操做的部分,放到DMA控制器上实现。而对于IO设备来讲,例如磁盘控制器并不知道或者并不关心,磁盘的读写请求是来自CPU仍是DMA控制器。当程序须要将文件中的某些字节拷贝到内存中的一块区域时,首先CPU告诉DMA控制器须要将什么数据传送到什么地方,而该进程(或者当前请求IO的线程)被挂起阻塞,接着DMA控制器向磁盘控制器发出命令,磁盘控制器寻道,寻址,将数据拷贝到磁盘控制器的缓冲区中。接着DMA控制器在总线上发出一个读请求给磁盘控制器,开始DMA传送。传输完成以后DMA控制器将中断CPU,以让CPU知道传输已经完成。接着中断服务程序开始运行,以前被挂起的进程(线程)继续开始运行,而此时文件的内容已经读到了指定的内存地址了。这期间没有占用CPU的时钟周期。数据结构

总结与其余

计算机系统是一个很是复杂与庞大的系统,以上的内容仅仅是一个入门的指引,限于篇幅不少细枝末节的内容都没有提到,若是有任何错误欢迎你们指出。另外计算机网络自己是一个很是大的课题因此我但愿用单独的一篇文章进行说明。另外留下一个问题,也是我有疑惑的地方,若是你们有答案,能够在留言区域讨论。多线程

问题:在单核CPU的架构下,多线程之间的锁其实相对比较容易实现,由于任什么时候刻其实只有一个进程的一个线程在占用CPU,所谓的并发其实是伪并发,真正的多核CPU的并发叫并行。单核CPU状况下,因为CPU轮转的很是快,让咱们看起来是同时运行了多个程序,那么问题是,若是在多个CPU的状况下,原来写的多线程程序的互斥与同步还有效果吗?由于极可能一个进程中的两个线程同时在两个不一样CPU上执行,他们访问同一个变量,这个加锁还有效果吗?架构

相关文章
相关标签/搜索