《程序员的自我修养》读书笔记(一)

1.第一章 温故而知新

1.1 从Hello World 说起

对于下面这样一个简单的Hello World程序, 提出以下的问题:

#include <iostream>
int main()
{
    printf("Hello World!") ;
    return 0;
}
  • 编译器编译产生的可执行文件中是什么?除了机器码还有什么?他们是怎么存放的?怎么组织的?
  • C语言库和运行时库是怎么回事?是怎么实现的?
  • Hello World 程序是怎么运行起来的,操作系统是怎么装载他的,他从哪里开始执行?到哪结束?main函数之前发生了什么?main函数结束之后又发生了什么?
  • Hello World程序运行时在内存中是什么样子

以上几个问题是我挑选出来概念比较模糊的。希望在后面的部分能够较好的解决这些疑惑

1.2 万变不离其宗

​ 计算机硬件有三个部分最为关键:CPU,内存,IO控制芯片。对于一些高级语言的开发者,基本上只需要关注CPU,对于提供虚拟机的一些语言,甚至连CPU都不需要关心。

IO控制芯片具体是哪些部件,是指声卡,显卡,磁盘控制器吗?

​ 早期,计算机CPU和内存速度相似,而IO设备速度慢很多,为了协调CPU与IO设备之间的速度,并且与之有较为统一的接口进行通信,为每个IO设备设计了IO控制器。当时,所有的IO控制器和CPU,内存是连接在同一条BUS上的。

​ 后来,随着CPU速度超越内存速度,CPU和内存通过一条系统总线进行通信,其中系统总线与内存速度一致,而CPU采用倍频的方式进行工作,接下来,由于图形化操作系统的普及,慢速的IO总线已经无法满足图形设备的巨大需求,为了协调CPU,内存和图形设备,人们设计了一个高速的北桥芯片,用于高速的交换数据。

​ 由于北桥速度非常高,所有的低速设备如果都直接连接在北桥上,会造成设计复杂,结构混乱,难以管理。因此,有设计了一个处理低速设备的南桥芯片,南桥将它们汇总之后,连接到北桥上。90年代起,北桥采用PCI结构,南桥采用ISA结构。虽然随着设备技术的发展,硬件系统的结构和类型有一些变化,但从程序开发的角度来看,可以将它看成最初的硬件模型。

SMP与多核

​ 在过去50年来,CPU的速度由几十KHZ增长到如今4GHZ,提高了数十万倍。基本上每18个月频率就会翻倍,但自从2004年开始,这种趋势似乎已经渐渐消失。原因大概在于CPU工艺方面已经逐渐逼近了物理极限,除非CPU制造工艺有本质的突破。

​ 对于摩尔定律的失效,在平时确实有切身体会。刚开始听同学说起摩尔定律失效的事情,以为是子虚乌有的谣传。然而渐渐发现CPU频率几年基本维持在同一水平,内存、闪存价格不降反增,特别是最近半年时间,同样性能价格近乎翻倍。不得不说,对于计算机行业的发展,这实在是个噩耗。

​ 由于单个CPU性能在短期内,难以有质的提升。因此人们开始从另一个角度提高CPU的速度,就是增加CPU的数量,即多核技术。

其中常见的一种形式就是SMP(对称多处理器),但由于很多程序难以简单的拆分成不相干的部分,在不同的CPU上运行,因而CPU的数量与性能并非是成正比的(理想情况下是可以成正比的)。就比如,一个农民一年可以收获1万斤粮食,12个农民并不能一个月就收获1万斤粮食。因此对于SMP的结构,最适合的应用场合就是大型的数据库系统或者是网络服务器上,它们需要同时处理大量类似或者相同的,并且相互独立的请求,可以最大程度的发挥SMP的威力。

​ 对于个人计算机来说,由于高昂的高速缓存(cache)价格,而且较少有理想的应用场景,多核计算机性价比较低。因此,人们通过将多个核心处理器打包在一起,共享同一块高速缓存,性价比有较大的提升,这就是超线程技术。实际上是SMP技术的简化版本。

1.3 站的高,望的远

​ 系统软件其实是个相当模糊的概念,一般将用于管理计算机自身的软件成为系统软件,以区别于普通的应用程序。系统软件可以分为两部分,一部分是平台性的,如操作系统内核,驱动程序,运行库和数以千计的系统工具;另一部分是用于程序开发的,比如编译器,链接器,汇编器等开发工具以及开发库。本书主要介绍链接器和库(包括运行库和开发库)的相关内容。

​ 计算机软件体系结构采用一种层的结构,有一句名言;

Any problem in computer science can be solved by another layer of indirection.

​ 系统软件体系结构中,各软件位置如图:

计算机体系结构

​ 每个层次之间都要进行相互通信,即存在通信协议,我们称作接口(Interface)。在层次结构中,接口是被精心设计过的,尽量保持稳定不变。那么理论上层次之间只要遵循这个接口,任何一个层都可以被修改或替换。

​ 开发工具和应用程序都使用API,API由运行时库提供。Linux下Glibc提供POSIX的API,Windows运行时库提供Windows API,最常见的32位Windows提供的API又被称为Win32。

​ 运行时库使用操作系统提供的系统调用接口(System call interface),系统调用往往以软件中断的形式提供。

​ 操作系统内核(Operating System kernel)对于硬件来说,是硬件接口的使用者,而硬件是接口的定义者,硬件接口的定义决定了操作系统内核。具体来讲就是驱动程序如何操作硬件,如何与硬件进行通信。这种接口往往被称作硬件规格(Hardware Specification)。开发者通过阅读硬件规格来编写操作系统和驱动程序。

1.4 操作系统做什么

​ 操作系统主要有两个功能,一是给上层软件开发提供一个统一的抽象的接口,二是管理和充分的利用硬件资源。

​ 计算机中的硬件资源主要有,CPU,内存和IO设备。

  • 不要让CPU打盹

    ​ 为了充分的利用CPU资源,操作系统由最初的单道程序设计多道程序设计,为了在一个程序释放CPU资源(等待IO,或者结束)时,自动的载入下一个程序到CPU中,极大的提高了CPU得利用率,但是对于程序的平均响应时间非常的慢。因此出现了分时系统,为每个程序分配固定的时间片,以降低CPU的平均响应时间。分时系统逐渐发展为现在的多任务系统,程序以进程的形式运行在内存中,操作系统接管了所有硬件资源,统一管理和分配给各个进程,通过优先级、轮转、抢占方式的结合来调度进程,以充分利用CPU资源。

  • 设备驱动

    ​ 作为程序的开发者,肯定不希望直接读写硬件接口,处理硬件中断。这些繁琐的硬件细节全都交给的操作系统,具体来说,是操作系统中的硬件驱动程序。硬件驱动程序可以看成是操作系统的一部分,往往与操作系统一起运行在特权级,但又有一定的独立性,是的硬件驱动程序有较好的灵活性。

    ​ 如文件的读取,操作系统中的文件系统管理着磁盘中文件的存储方式。当文件系统收到一个读文件前4096字节的read请求后,先计算对应数据的逻辑扇区位置,然后文件系统向磁盘驱动程序发出相应的读取请求。有厂商开发的磁盘驱动程序通过相应的磁盘接口规格,按照一定的步骤并遵循某些特定的规则,读写端口寄存器,最终将文件数据读取到指定的内存位置。

1.5 内存不够大怎么办

​ 如何将计算机有限的物理内存分配给多个程序使用?直接分配物理内存的话主要会产生以下问题:

  • 地址空间不隔离

    考虑程序安全性和独立性问题

  • 内存使用效率低

    考虑内部和外部碎片以及换入换出问题

  • 程序运行地址不确定

    程序在汇编时,就有许多跳转指令与寻址指令需要将具体的标号或变量地址确定下来,用以生成机器码,地址不确定会涉及到重定位等问题。

解决以上问题的方法就是:增加中间层虚部地址

​ 虚拟内存的机制通过分页和分段的策略来实现。其中分段解决了地址不隔离和程序运行地址不确定的问题,而分页解决了内存使用效率的问题。通常CPU中集成一个MMU(Memory management unit ) 来管理虚拟地址,进行虚拟地址与物理地址的映射。

1.6 众人拾柴火焰高

1.6.1 线程基础

​ 在软件系统中,进程和线程都是十分重要的概念。特别是随着CPU向多核发展,多线程作为实现软件并发执行的一个重要方法,也开始具有越来越重要的地位。

  • 什么是线程

    ​ 线程是程序执行的最小单元,有ID,寄存器,堆栈,PC等组成,可以看做是一部分CPU资源的抽象。进程由线程组成,是计算机中一部分硬件资源的抽象实现,除了CPU资源外,它还包括内存,IO等硬件资源。

1.6.2 线程安全

​ 多线程容易产生Race Condition,一般来说通过精心的程序设计,信号量,条件变量,管程,硬件或操作系统提供的原子操作来避免。

​ 而编译器和CPU的过度优化常常会是以上的同步方式失效,当考虑到这些情况时,多线程程序设计考虑的因素将更加复杂。

  • 可重入与线程安全

    ​ 可重入是一个很有趣的概念,当多个线程同时执行某段代码,或其递归调用自身时发生重入,可重入的程序设计是并发执行的强力保障。

1.6.3 多线程内部情况

  ​线程的并发执行时多处理器或操作系统通过调度实现的。用户线程通过映射到内核线程来调入CPU执行。映射方式通常有三种:
  • 一对一模型

  • 一对多模型

  • 多对多模型

    多对多结合了前两者的优点,消除了部分缺点。但实现更困难。

1.7 本章小结

​ 本章回顾了整个计算机软硬件的基本结构。包括CPU与外围部件的连接方式,SMP与多核,软硬件层次体系结构,如何充分利用CPU,与系统软件相关的设备驱动,操作系统,虚拟、物理空间,段页式管理和线程的相关概念。

猜你喜欢

转载自blog.csdn.net/renjiewen1995/article/details/54780674