程序员的自我修养阅读笔记(1)

来源:互联网 发布:c语言好的书籍 编辑:程序博客网 时间:2024/06/05 07:12

第一章:温故而知新

南桥:处理低俗设备

北桥:处理高速设备


名言警句

any problems in computer science can be solved by another layer of indirection.


在层次体系中,接口是被精心设计过的,尽量保持稳定不变,那么理论上层次之间只要遵循这个接口,任何一个层次都可以被修改或替换。

在尽可能少改甚至不改变其它层的情况下,新增加一个层次就可以提供前所未有的功能。


系统调用接口往往以软中断的方式提供。


文件系统保存了这些文件的存储结构,负责维护这些数据结构并且保证磁盘中的扇区能够有效的组织和利用。


每个进程都有自己的虚拟空间,而且每个进程只能访问自己的地址空间,这样就有效的做到了进程的隔离。


分页的基本方法是把地址空间人为地等分成固定大小的页,每一页的大小有硬件决定。

在页映射模式下,CPU发出的是虚拟地址,即我们的程序看到的是虚拟地址,经过MMU转换以后就变成了物理地址。


一个标准的线程由线程ID,当前指令指针,寄存器集合,寄存器集合和堆栈组成。

一个进程由一个或多个线程组成,各个线程之间共享程序的内存空间(包括代码段,数据段,堆等)及一些进程级的资源(如打开的文件和信号);


我们一般把频繁等待的线程称之为IO密集型线程,把很少等待的线程称为CPU密集型线程。IO密集型线程总是比CPU密集型线程容易得到优先级的提升。

为了避免饿死现象,调度系统常常会逐步提升那些等待了过长时间的得不到执行线程的优先级。


写时复制两个任务可以同时自由的读取内存,但任意一个任务试图对内存进行修改时,内存就会复制一份提供给修改方单独使用,以免影响其他任务的使用。


fork只能够产生本任务的镜像,要使用exec用新的可执行镜像替换当前的可执行镜像,因此fork产生了一个新任务后,新任务可以调用exec来执行新的可执行文件。


线程安全:

同步与锁

(1)二元信号量(Binary Semaphore)

最简单的一种锁,只有两种状态:占用与非占用,它适合只能被唯一一个线程独占访问的资源。

信号量在整个系统中可以被任意的线程获取并释放,也就是说,同一个信号量可以被系统中的一个线程获取之后由另一个线程释放。

(2)互斥量(Mutex)

和二元信号量类似,但是互斥量要求那个线程获取了互斥量,哪个线程就要负责释放这个锁。

(3)临界区(Critical Section)

是比互斥量更严格的同步手段。临界区和互斥量与信号量的区别在于,互斥量和信号量在系统的任何线程都是可见的。

而临界区的作用仅限于本进程。

(4)条件变量(Condition variable)

条件变量作用类似一个栅栏。使用条件变量可以让许多进程一起等待某个事件的发生,当事件发生时(条件变量被唤醒),所有的线程

可以一起恢复。


volatile关键字试图中阻止过度优化

(1)阻止编译器为了提高速度将一个变量缓存到寄存器内而不写会;

(2)阻止编译器调整操作volatitle变量的指令顺序。

(3)但无法阻止CPU动态调换顺序。


许多体系结构的CPU都会提供barrier指令,一条barrier指令会阻止CPU将指令之前的指令交换到barrier之后。


C++里new其实包含了两个步骤

(1)分配内存

(2)调用构造函数。


第二章编译和链接

从程序源代码到最终可执行的文件的4个步骤:

(1)预编译   (2)编译   (3)汇编     (4)链接

(1)预编译:主要是处理那些源代码中的以“#”开始的预编译指令。

(2)编译:把预处理的文件进行一系列的词法分析、语法分析、语义分析及优化后产相应的汇编代码文件

(3)汇编;将汇编代码转变成机器可以执行的指令。

(4)链接:终主要包括了地址和空间分配,符号决议(Symbol Resolution)和重定位(Relocation).

重新计算各个目标地址的过程被叫做重定位。