程序员的自我修养 学习笔记(1)
本文源自在学习《程序员的自我修养》中的心得体会。
对于底层系统程序开发者来说,硬件平台可以抽象为三个主要部件,CPU、内存、I/O控制器。
早期的计算机没有复杂的图形功能,CPU和内存之间的频率差异不大,它们都是连接在同一个bus上面的。其他I/O设备,诸如显示设备、键盘、磁盘等速度比内存、CPU慢很多。为了IO设备与CPU、内存之间的协调通讯,一般每个IO设备商都有相应的IO控制器,早期的硬件结构图如下:
随着技术的进步,CPU的频率越来越高,内存跟不上CPU的速度,他们之间就需要一个转换机构,他们之间通过系统总线相连,CPU通过倍频的方式与系统总线通讯,内存直接连在系统总线上。
随着图形化系统和多媒体的发展,CPU处理图形的负担越来越重,需要显示芯片来分担CPU的任务。图形芯片需要和CPU、内存之间大量交换数据,慢速IO总线已经不能满足要求了,为了协调CPU、内存和显卡之间的速度关系,专门设计了高速的北桥芯片,以便他们之间高速交换数据。
如果让北桥芯片(PCI总线),同时处理高速数据和低速数据,设计和实现会十分复杂。人们又专门设计出了适合低速设备的南桥芯片,磁盘、USB、键盘、鼠标等都接在南桥芯片上,由南桥(ISA总线)统一汇总,接到北桥芯片中去。
随着人们需求的增长,PCI的133MHz的速度已经满足不了, 人们开发出了AGP、PCI Express等新的总线,但是,他们还是没有脱离最初的CPU、内存、IO控制器的基本结构。
由于芯片制作工艺和物理材料的限制,CPU的频率会限制在4GHz的天花板上。为了进一步提高速度,人们想到通过增加CPU的数量来增加处理速度。理论上,增加CPU数量,可以提高运算速度,实际上并不是如此。例如,一个女人需要花10个月生育一个孩子,但是10个女人,不能在一个月内生育一个孩子。
计算机系统软件体系结构采用层次结构,有一句名言:
“计算机科学领域的任何问题都可以通过增加一个间接的中间层来解决”
操作系统的应用程序编程接口(Application Programming Interface)是由运行库来提供的,运行库使用操作系统提供的系统调用接口(System call Interface),系统调用接口往往通过软中断(Software Interrupt)的方式来实现。
比如,Linux下面的Glibc库提供的POSIX的API,系统调用接口中断为0x80号中断。
WIndows的运行库提供Windows API,系统调用接口中断为0x2E号中断(Xp2开始,采用新的系统调用方式)
内存分段,将应用程序A(以 0x0000~0x3fff 空间为例子),应用程序B(以0x0000~0x2fff),分段映射到实际物理内存上。做到了地址隔离,不需要重定位,没有解决多程序的内存使用效率问题(如果内存不足,换入换出的是整个程序,造成大量的磁盘访问操作)。
由于程序的局部性原理,在一个程序运行期间,在某个时间段,它只是频繁的用到了一小部分数据。于是,人们提出了更小的内存粒度分隔方式和映射的方法,这就是分页。
内存分页,将虚拟地址空间人为地分为固定大小的页(由硬件决定页大小,由操作系统选择页大小)。一般,页大小为4KB。每个页可以设置权限属性,起到保护的作用。虚拟存储需要MMU支持(MMU一般集成在CPU内),结构如下:
线程与进程的马车例子
线程调度方法,基本的有优先级调度(Priotiry Schedule)和轮转法(Round Robin)
线程安全的机制:原子操作,锁,二元信号量,多元信号量,互斥量,临界区,
互斥量与二元信号量很类似,资源仅仅同时允许一个线程访问,但和信号量不同的时候,信号量在整个系统可以被任意线程获取并释放。互斥量要求,被哪个线程获取,就一定要由哪个线程来释放。
可重入函数:
防止编译器过度优化:volatile关键字
防止CPU的乱序执行:barrier指令