《CSAPP》第一章 计算机系统漫游

关于为什么要重读计算机经典书籍?

  大量的新技术其实只是一层皮,背后的支撑技术其实都是十来年不变的东西。底层知识永不过时;算法数据结构永不过时;分析问题和解决问题的能力永不过时;强大的学习能力和旺盛的求知欲永不过时;你大脑的思维方式永不过时。
  关于读书速度,有选择地阅读。 对于一些逻辑混乱,作者都不知道自己问题是什么,或者上来就是技术方法细节,而不是从方法背后的理念出发,直观解释的书,没必要一定说服自己读下去,继续读反而是增加烦恼,浪费时间。
  快or慢。 快慢从来不是一个问题,好书、知识密度大、需要思考的书就慢读。质量差,没啥的,该快就快,有必要过一遍的话,该不读就直接扔一边去,没必要纠结。
  “三天打鱼,两天晒网”的人往往最后会变成“整天晒网,永不打鱼”。也就是说耐心和恒心吧。一本再厚的书,每天看一点,总有看完的一天。
– <暗时间>

概述

  什么是计算机系统?它和操作系统有何不同?我们为什么要深入理解计算机系统?概括的讲计算机系统是由硬件和系统软件共同组成的,它们通过共同的协作来运行应用程序。而我们在日常编写程序时使用的文件、内存、进程等概念都是为了程序编写的方便,由实际的计算机系统高度抽象而来。这一章中我们使用 c 语言编写简单的 hello 程序,试图通过跟踪 hello 程序的生命周期来窥探计算机系统的全貌。

//hello.c
#include <stdio.h>

int main()
{
	printf("hello, world\n");
	return 0;
}
//编译
linux > gcc hello.c -o hello
计算机中代码编译流程
  • 预处理(Pre-processor(.cpp)):读取c源程序,对其中的伪指令(以# 开头的指令)和特殊符号进行处理。[伪指令包括:宏定义指令、条件编译指令、头文件包含指令等]
  • 编译(Compiler(.ccl)) :编译过程就是对预处理完的文件进行一系列的词法分析,语法分析,语义分析及优化后生成相应的汇编代码。
  • 汇编(Assembler(.as)):汇编器根据指令集将汇编程序翻译成机器指令,并且按照一系列的机器指令按照固定的规则进行打包,得到 ELF(Executable and Linkable Format)格式的可重定向文件。
  • 链接(Linker(.ld)):分为静态链接与动态链接。静态链接(指在编译阶段直接将静态库加入到可执行文件中去,链接器实现符号解析与重定位),动态链接(在链接阶段仅仅之加入一些描述信息,而程序执行时再从系统中把相应动态库加载
    到内存中去)。

为什么要理解编译系统是如何工作的?1、可以优化程序的性能。2、理解链接时出现的错误。3、避免安全漏洞
编译流程

处理器如何读并解释储存在内存中的指令
linux> ./hello
hello, world

   编译好的可执行文件被存在在磁盘上。要想在Unix系统上运行该可执行文件,将目标文件的文件名输入到shell中运行。
  把它加载到内存中运行,shell 是操作系统中的命令行解释器,它将我们输入的文件名和回车解释为执行 hello 程序。
  于是 hello 程序将会被加载到内存中去执行,并在执行过程中输出程序中的 “hello, world” ,那么在计算机内程序的执行经历了哪些过程是值得探究的。

计算机系统的硬件组成

  计算机硬件由总线、I/O设备、主存、处理器四个主要部分组成。

  • 总线:贯穿整个系统的电子管道,用于数据和指令在计算机不同组件之间传输和控制。通常总线被设计成传送定长的字符块,即字。在32位机中一个字4个字节(4 * 8 = 32位),在64位机中一个字8个字节 (8 * 8 = 64位)。
  • I/O设备:I/O(input/output)设备,是系统与外部世界的联系通道,鼠标、键
    盘、显示器、一起磁盘都是I/O设备。(可执行程序hello 最开始就存放在磁盘上)。每一个I/O设备都通过一个控制器或者适配器与I/O总线相连。控制器和适配器之间的区别主要在于它们的封装方式。控制器是I/O设备本身或者系统的主印刷电路(通常称为主板)上的芯片组。而适配器则是一块插在主板插槽上的卡。但是它们的功能都是I/O总线与I/O设备之间传递信息。
  • 主存:主存就是我们常说的运行内存,由一组动态随机存储器(DRAM)芯片组成。从逻辑上来说,存储器是一个线性的字节数组,每个字节都有其唯一的地址(数组引索),这些地址是从0开始的。在主存中程序运行时变量的数据大小是根据类型变换的。比如在运行 linux 的 x86-64 机器上,short 类型2个字节、int 和 float 类型四个字节,而 long 和 double 则需8个字节。
  • 处理器:中央处理的单元(CPU),是解释或执行存储在主存中指令的引擎。处理器主要由程序计数器PC和算术/逻辑单元ALU还有寄存器组成。程序计数器PC也是一个大小一个字的寄存器,在任何时候PC指向主存中的某条机器语言指令。算术/逻辑单元ALU则来实现算术和逻辑的运算。

  处理器的运行过程

  • 加载:从主存中加载数据到寄存器
  • 存储:从寄存器中复制数据到主存
  • 操作:把两个寄存器的内容复制到ALU做算术运算,将结果存放在一个寄存器中。
  • 跳转:从指令中抽取一个字复制到PC中以覆盖原来内容。
    计算机系统硬件
计算机中存储器的层次结构

  通过hello 文件在计算机中的执行过程,不难发现一个问题,即系统花了大量的时间把信息从一个地方挪到另一个地方。根据机械原理,容量越大的存储设备往往速度越慢,而主存和磁盘的读写速度则远小于CPU的处理速度。这样就造成了速度的不匹配,使运行 hello 程序时,在传输数据的过程中浪费了很多时间。
  针对这种差异,于是设计者开发了更小更快的存储设备,成为高速缓存存储器(cache memory),并将其放在处理器中直接与寄存器连接,将处理器常用的数据存放在其中,避免了频繁的从主存或磁盘中传输数据。如现在计算机处理器常有L1和L2高速缓存,处理能力更强大的处理器甚至有三级高速缓存:L1、L2和L3。
  在计算机中,存储器的速度由快到慢,容量由小到大形成了计算机的存储器层次结构:
  因此,意识到高速缓存存储器存在的应用程序员能够利用高速缓存将程序的性能提高一个数量级。
计算机存储结构

操作系统管理硬件

  回到 hello 程序的例子,当shell加载运行hello程序,以及输出显示"hello world",shell和hello程序都没有直接访问主存、磁盘、显示器或键盘。取而代之它们依赖的是操作系统提供的服务,即向应用程序提供的系统调用。
  操作系统有两个基本功能:

  • 防止硬件被失控的应用程序滥用
  • 向应用程序提供简单移植的机制来控制复杂而又通常大不同的低级硬件设备。
    计算机分层

  而操作系统是通过几个基本抽象概念(进程/线程、虚拟内存、文件)来实现功能的,文件是对I/O设备的抽象表示,虚拟内存是对主存和磁盘I/O设备的抽象表示,进程则是对处理器、主存和I/O设备的抽象表示。如图:
操作系统抽象
进程
  进程是操作系统对一个正在运行的程序的一种抽象。在一个系统上可以同时运行多个进程,而每个进程都好像在独占地使用硬件。
  并发是指一个进程的指令和另一个进程的指令是交错执行的。
  在大多数系统中, 需要运行的进程数是多于可以运行它们的CPU个数的。传统系统在一个时刻只能执行一个程序,而先进的多核处理器同时能够执行多个程序。
  无论是单核还是多核系统中,一个CPU看上去都像是在并发地执行多个进程,这是通过处理器在进程间切换来实现的,操作系统把这种交错执行的机制叫做上下文切换
  操作系统保持跟踪进程运行所需的所有状态信息,这种状态,就是上下文。包括许多信息,比如说PC和寄存器文件的当前值,以及主存的内容。
  以hello程序的执行来解析:使用linux命令来执行hello程序,有两个并发的进程(shell进程与hello进程),最开始,只有shell进程在运行,即等待命令行的输入。当我们让它运行hello程序时,shell通过调用一个专门的函数,即系统调用,来执行我们的请求,系统调用会将控制权传递给操作系统。操作系统保存shell进程的上下文,创建一个新的hello进程及其上下文,然后将控制权传给新的hello进程。hello进程终止后,操作系统恢复shell进程的上下文,并将控制权传回给它,shell会继续等待下一个命令的进入。
  从一个进程切换到另一个进程的转换是由操作系统内核(kernel)管理的。内核是操作系统代码常住主存的部分。当应用程序需要操作系统的某些操作时,比如读写文件,他就是执行一条特殊的系统调用(system call)指令,将控制权传递给内核。然后内核执行被请求的操作并返回应用程序。注意,内核不是一个独立的进程。相反,它是系统管理全部进程所用代码和数据结构的集合。
进程的上下文切换
线程
   在现代操作系统中,一个进程实际上由一个或多个称为“线程”的执行单元组成,每个线程都运行在进程的上下文中,并共享同样的代码和全局数据。
   由于网络服务器中对并行处理的需求,线程称为越来越重要的编程模型,因为多线程之间比多进程之间更容易共享数据,也因为线程一般来说都比进程更高效。
   当有多处理器可用的时候,多线程也是一种使得程序可以运行得更快的方法。
虚拟内存
   虚拟内存是一个抽象概念,它为每个进程提供了一个假象,即每个进程都在独占地使用主存。每个进程看到的内存都是一致的,称为虚拟地址空间。下图是Linux进程的虚拟地址空间:
虚拟地址空间
  地址有下往上增大,从低地址网上分析:

  • 程序代码和数据。对所有的进程来说,代码是从同一固定地址开始,紧接着的是和C全局变量相对应的数据位置。代码和数据区是直接按照可执行目标文件的内容初始化的。在上面的程序中就是可执行文件hello
  • 。代码和数据区后紧跟的是运行时堆。代码和数据区在进程一开始运行时就被指定了大小,与此不同,当调用像malloc和free这样的C标准库函数时,堆可以在运行时动态地扩展和收缩。
  • 共享库。大约在地址空间的中间部分是一块用来存放像C标准库和数学库这样的共享库的代码和数据的区域。
  • 位于用户虚拟地址空间顶部的是用户栈,编译器用来实现函数调用。和堆一样,用户栈在程序执行期间可以动态地扩展和收缩。特别地,每次调用一个函数时,栈就会增长;从一个函数返回时,栈就会收缩。栈的增长方向是高地址往低地址
  • 内核虚拟内存地址空间顶部的区域是为内核保留的。不允许应用程序来读写这个区域的内容或者直接调用内核代码定义的函数。相反,它们必须调用内核来执行这些操作。虚拟内存的运作需要硬件和操作系统软件之间精密复杂的交互,包括对处理器生成的每个地址的硬件翻译。基本思想是把一个虚拟内存的内容存储在磁盘上,然后用主存作为磁盘的高速缓存。

文件
  文件就是字节序列,仅此而已。每个I/O设备,包括磁盘、键盘、显示器,甚至网络,都可以看成是文件。系统中的所有输入输出都是通过使用一小组称为Unix I/O的系统函数调用读写文件来实现的。
  文件这个简单而精致的概念是非常强大的,因为它向应用程序提供了一个统的视图,来看待系统中可能含有的所有各式各样的I/O设备。例如,处理磁盘文件内容的应用程序员可以非常幸福,因为他们无须了解具体的磁盘技术。进一步说,同一个程序可以再使用不同磁盘技术的不同系统上运行。

网络
  从一个单一的系统来看,网络可以视为一个I/O设备。如图,当系统复制一串字节到网络适配器时,数据流经过网络到达另一台机器,相似的,系统也可以读取从其他机器发来的数据。
网络I/O
  在现代计算机中客户端和服务器之间的交互是很常见的,就像一些连接服务器用的远程客户端,例ssh。我们可以将它连接到服务器并且运行服务器上的 hello 程序。网络交互

一些重要概念

  总结几个贯穿计算机系统所有方面的重要概念
Amdahl定律
  该定律的主要思想是:当我们对系统的某个部分加速时,其对系统整体性能的影响取决于该部分的重要性和加速程度。
Amdhal定律
并发与并行
  数字计算机的整个历史中,有两个需求是驱动进步的持续动力:一个是我们想要计算机做得更多,另一个是我们想要计算机运行得更快。当处理器同时做更多的事情时,这两个因素都会改进。
  这里有两个概念,并发指一个同时具有多个活动的系统;并行指的是用并发来使一个系统运行得更快,它可以在计算机系统的多个抽象层次上运用。
  如何获得更高的计算能力呢?三个途径:线程级并发,指令级并行,单指令多数据并行

  • 线程级并发:构建在进程这个抽象之上,我们能够设计出同时有多个程序执行的系统,这就导致了并发。在单处理系统时代,这种多线程并发只是模拟出来的,通过计算机在它执行的进程间快速切换来实现的。直到多核和超线程技术的出现,使得了程序可以利用硬件实现真正的线程级并发性。多核处理器时代,处理器将多个CPU集成到一个集成电路上;还出现了超线程技术,超线程有时被成为同时多线程,是一个允许CPU执行多个控制流的技术,例如Intel Core i7处理器可以让每个核执行两个线程。传统处理器线程的切换大约需要20 000个时钟周期,而超线程技术通过对CPU某些硬件的备份,例如PC和寄存器,是CPU能够在单个时钟周期的基础上决定执行那个线程。多处理器的使用可以从两个方面提高系统性能。首先,减少了执行多个任务时模拟并发的需要。其次,它可以使应用程序运行得更快,当然,这必须要求程序是以多线程方式来书写的。
  • 指令级并行:在低一些的层次上,现在处理器可以通过同时执行多条指令的属性称为指令级并行。通过流水线技术,将执行每条指令所需的步骤(取值、译码、执行等)根据它们使用的硬件资源不同将多个指令不发生冲突的步骤放到一起并行执行,使得处理器达到接近一个时钟周期执行一条指令的执行速度。如果处理器可以达到比一个周期一条指令更快的执行速率,就称之为超标量处理器。现代大多数处理器都支持超标量操作。
    指令级并行
  • 单指令多数据并行:在最低的层次上,许多现代处理器拥有特殊的硬件,允许一条指令产生多个可以并行的操作,这种方式被称为单指令、多数据,即SIMD并行。例如,较新几代的Intel和AMD处理器具有并行的对8对单精度浮点数做加法的指令,可以提高影像、声音和视频数据应用的执行速度。

计算机系统中抽象的重要性
  抽象的使用是计算机科学中最为重要的概念之一,前面提到文件是对I/O设备的抽象,虚拟内存是对程序存储器的抽象,而进程是对一个正在运行的程序的抽象。那么,虚拟机是对整个计算机的抽象,包括操作系统、处理器和程序。
计算机抽象

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/Frank_sample/article/details/115498252

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值