HelloWord
文件名hello.c 的源程序实际上就是一个由值 0 到 1 组成的位(又称为比特)序列,8 个位被组织成一组,成为字节。每个字节表示程序中的某些文本字符。
大部分的现代计算机系统都使用 ASCII 标准来表示文本字符,这种方式实际上就是用一个唯一的单字节大小的整数值来表示每个字符。
像 hello.c 这样只由 ASCII 字符构成的文件称为文本文件,所有其他文件都称为二进制文件。
hello.c 的表示方法说明了一个基本思想:系统中所有的信息 – 包括磁盘文件、内存中的程序、内存中存放的用户数据以及网络上传送的数据,都是由一串比特表示的。
系统的硬件组成
总线
贯穿整个系统的是一组电子管道,称作总线,它携带信息自己负责在各个部件间传递。通常总线被设计成传送定长的字节块,也就是字(word)。字中的字节数(即字长)是一个基本的系统参数,各个系统中都不尽相同。现在大多数机器字长要么是 4 个字节(32 位),要么是 8 个字节(64 位)。
I/O 设备
I/O(输入/输出)设备是系统与外部世界的联系通道。包括 作为用户输入的键盘和鼠标,作为用户输出的显示器,以及用于长期存储数据和程序的磁盘驱动器(简单说就是磁盘)。
每个I/O设备都通过一个控制器或设配器与I/O总线相连。控制器和适配器之间的区别在于它们的封装方式。
- 控制器是I/O设备本身或者系统的主印制电路板(通常称作主板)上的芯片组。
- 适配器则是一块插在主板插槽上的卡
无论如何,它们的功能都是在I/O总线和I/O设备之间传递信息。
主存
主存是一个临时存储设备,在处理器执行程序时,用来存放程序处理的数据。
从物理上来说,主存是由一组动态随机存取存储器(DRAM)芯片组成。
从逻辑上来说,存储器是一个线性的字节数组,每个字节都有其唯一的地址(数组索引),这些地址是从零开始的。一般来说,组成程序的每条机器指令都由不同数量的字节构成。
处理器
中央助理单元(CPU) ,简称处理器,是解释(或执行)存储在主存中指令的引擎。处理器的核心是一个大小为一个字的存储设备(或寄存器),称为程序计数器(PC)。在任何时刻,PC 都指向主存中的某条机器语言指令(即含有该条指令的地址)。
从系统通电开始,直到系统断电,处理器一直在不断地执行程序计数器指向的指令,再更新程序计数器,使其指向下一条指令。处理器从程序计数器指向的内存处读取指令,解释指令中的位,执行该指令指示的简单操作,然后更新 PC 使其指向下一条指令,而这条指令并不一定和在内存中刚刚执行的指令相邻。
CPU 在指令的要求下可能会执行这些操作:
- 加载:从主存复制一个字节或者一个字到寄存器,以覆盖寄存器原来的内容。
- 存储:从个寄存器复制一个字节或者一个字到主存的某个位置,以覆盖这个位置上原来的内容。
- 操作:把两个寄存器的内容复制到 ALU, ALU 对这两个字做算术运算,并将结果存放到一个寄存器中,以覆盖该寄存器中原来的内容。
- 跳转:从指令本身中抽取一个字,并将这个字复制到程序计数器(PC)中,以覆盖 PC 中原来的值。
运行 hello 程序
初始时,shell 程序执行它的指令,等待我们输入一个命令。当我们在键盘上输入字符串“./hello”后,shell 程序将字符逐一读入寄存器,再把它存放到内存中,如下图:
当我们在键盘上敲回车键时,shell 程序就知道我们已经结束了命令的输入。然后 shell 执行一系列指令来加载可执行的 hello 文件,这些指令将 hello 目标文件中的代码和数据从磁盘复制到主存。数据包括最终会被输出的字符串“hello, world\n”。
一旦目标文件 hello 中的代码和数据被加载到主存,处理器就开始执行 hell 程序的 main 程序中的机器语言指令。这些指令将“hello, world\n” 字符串中的字节从主存复制到寄存器文件,在从寄存器文件中复制到显示设备,最终显示在屏幕上,如下图:
高速缓存
处理器读取并解释存放在主存里的二进制指令。因为计算机花费了大量的时间在内存、I/O设备和 CPU 寄存器之间复制数据,所以将系统中的存储设备划分层次结构:
CPU 寄存器在顶部,接着是多层的硬件高速缓存存储器、DRAM 主存和磁盘存储器。在层次模型中,位于更高层的存储设备比底层的存储设备要更快,单位比特造价也更高。层次结构中较高层次的存储设备可以作为较低层次设备的高速缓存。
进程
进程是操作系统对一个正在运行的程序的一种抽象。就好像系统上只有这个程序在运行。程序看上去是度占地使用处理器、主存和 I/O 设备。处理器看上去就像在不间断地一条接一条地执行程序中的指令,即该程序的代码和数据是系统内存中唯一的对象。这些假象是通过进程的概念来实现的,进程是计算机科学中最重要和最成功的概念之一。
上下文
操作系统保持跟踪进程运行所需的所有状态信息。这种状态,也就是上下文,包括许多信息,比如 PC 和寄存器文件的当前值,以及主存的内容。在任何一个时刻,单处理器系统都只能执行一个进程的代码。当操作系统决定要把控制权从当前进程转移到某个新进程时,就会进行上下文切换
,即保存当前进程的上下文、恢复新进程的上下文,然后将控制权传递到新进程。新进程就会从它上次停止的地方开始。
上图中有两个并发的进程:shell 进程 和 hello 进程。最开始,只有 shell 进程再运行,即等待命令行上的输入。当我们让它运行 hello 程序时,shell 通过调用一个专门的函数,即系统调用,来执行我们的请求,系统调用会将控制权传递给操作系统。操作系统保存 shell 进程的上下文,穿件一个新的 hello 进程及其上下文,然后将控制权传给新的 hello 进程。hello 进程终止后,操作系统恢复 shell 进程的上下文,并将控制权传回给它,shell 进程会继续等待下一个命令行输入。
上图,从一个进程到另一个进程的转换是由操作系统内核
管理的,内核是操作系统代码常驻主内存的部分。当应用程序需要操作系统的某些操作时,比如 读写文件,它就执行一条特殊的系统调用(system call)指令,将控制权专递给内核。然后内核执行被请求的操作并返回应用程序。注意,内核不是一个独立的进程。相反,它是系统管理全部进程所用代码和数据结构的集合。
操作系统内核,是应用程序和硬件之间的媒介。它提供三个基本的抽象:
- 文件是对 I/O 设备的抽象;
- 虚拟内存是对主存和磁盘的抽象;
- 进程是处理器、主存和 I/O 设备的抽象。
线程
尽管通常我们认为一个进程只有单一的控制流,但是在现代系统中,一个进程实际上可以由多个称为线程的执行单元组成,每个线程都运行在进程的上下文中,并共享同样的代码和全局数据。
Amdahl 定律:该定理的主要思想是,当我们对系统的某个部分加速时,其对系统整体性能的影响取决于该部分的重要性和加速程度。
完
现在是过去的积累,也是对过去的坏习惯买单,
未来是现在的积累。
我们只有好好把握当下,认真做好手里的每件事情,才能离理想中的自己更进一步。