《程序员的自我修养——链接、装载与库》读书笔记(一)

336 阅读4分钟

温故而之新

带着问题看本书

#include <stdio.h> 
int main() { 
    printf("Hello World\n"); return 0; 
}
  • 程序为什么要被编译器编译了之后才可以运行?
  • 编译器在把 C 语言程序转换成可以执行的机器码的过程中做了什么,怎么做的?
  • 最后编译出来的可执行文件里面是什么?除了机器码还有什么?它们是怎么存放的,是怎么组织的?
  • #include<stdio.h> 是什么意思?把 stdio.h 包含进来意味着什么?C 语言库又是什么?它是怎么实现的?
  • 不同的编译器和不同的硬件平台以及不同的操作系统,最终编译出来的结果是一样吗?为什么?
  • Hello World 程序是怎么运行起来的?操作系统是怎么装载它的?它从哪儿开始执行,到哪儿结束?main 函数之前发生了什么?main 函数结束之后又发生了什么?
  • 如果没有操作系统,Hello World 可以运行吗?如果要在一台没有操作系统的机器上运行 Hello World 需要什么?应该怎么实现?
  • printf 是怎么实现的?它为什么可以有不定数量的参数?为什么它能够在终端上输出字符串?
  • Hello World 程序在运行时,它在内存是什么样子的?

计算机的体系结构

  • 计算机硬件的多如牛毛,其中三个部件最为关键:CPU、内存、IO控制芯片
  • 北桥芯片:协调CPU、内存和高速的图形设备锁设计。其中高速的硬件设备连接北桥,低俗连接南桥。
  • 对称多处理器(SMP)多CPU
  • 一个处理器多核芯(多核处理器)
  • 硬件提供应用程序的编程接口。目前我们编写驱动程序,由操作系统和硬件进行对接

操作系统

  • 操作系统提供抽象的接口、管理硬件资源
  • 应用程序以进程的方式在操作系统中运行,目前CPU的分配方式为抢占式(操作系统拥有主导权,可以强制收回进程占用的cpu资源)
    程序使用物理地址的缺陷:
    1. 地址空间不隔离 程序间可以任意修改数据
    2. 内存使用效率低 大量数据换入换出
    3. 运行地址不稳定 每次运行时,从内存区域分配一个较大区域,空闲区域位置不确定
  • 虚拟地址: 隔离物理地址和程序,虚拟地址映射到物理地址,可以隔离地址空间
  • 内存分页:把地址空间人为地等分成固定大小的页。一般 4KB。把常用的数据和代码装载到内存中,把不常用的代码和数据保存在磁盘里,当需要用到的时候再把它从磁盘中取出来。保存也是页映射的目的之一,简单说就是可以设置每个页的权限属性,谁可以修改,谁可以访问。映射是依靠硬件支持的。MMU(Memory Management Unit),一般集成在 CPU 内部。

线程基础

线程组成: 线程ID、当前指令指针(PC)、寄存器集合和堆栈组成

时间片: 线程可以执行的一段时间

访问权限

私有

  • TLS
  • 寄存器(包括PC寄存器) 公有
  • 全局变量
  • 静态变量
  • 代码
  • 打开的文件

线程根据优先级进行调度: 频繁等待的线程称为IO密集型及线程,更容易拿到优先级

线程优先级改变的方式

  1. 用户指定优先级
  2. 根据进入等待状态的频繁程度提升或者降低优先级
  3. 长时间得不到执行而被提升优先级

抢占线程: 线程时间片用尽被强制进入ready状态,叫做抢占

不可抢占:不可被其他线程抢占

同步与锁

  • 二元信号量:两种状态,占用、非占用
  • 互斥量: 哪个线程获取,哪个线程释放
  • 临界区:作用范围为本线程
  • 读写锁
  • 条件变量 初始值为N,完成减一

用户线程与内核线程是多对多的关系,防止一个线程阻塞影响其他线程