(转)程序员的自我修养:温故而知新

目录

1.1从hello world说起

1.2变不离其宗

1.3站得高,看得远

1.4操作系统做了什么

  1.4.1不要让CPU打盹

1.5内存不够怎么办

  1.5.1关于隔离

  1.5.2分段

  1.5.3分页

1.6众人拾柴火焰高

  1.6.1线程基础

  1.6.2线程安全

  1.6.3多线程的内部情况

正文:

1.1从hello world说起

  目的:从最基本的编译,静态链接到操作系统如何转载程序,动态链接及运行库和标准库的实现,和一些操作系统的机制。了解计算机上程序运行的一个基本脉络。

1.2变不离其宗

  计算机最关键的三个部分:CPU,内存,I/O控制芯片。

  早期的计算机:没有复杂的图形功能,CPU和内存频率一样,都连接在一个总线上。

  CPU频率提升:内存跟不上CPU,产生了和内存频率一致的系统总线,CPU使用倍频的方式和总线通信。

  图形界面的出现:图形芯片需要和内存和CPU大量交换数据,慢速的I/O总线无法满足图形设备的巨大需求。为了高效处理数据,设计了一个高速的北桥芯片。后来有设计处理低速处理设备南桥芯片,磁盘,USB,键盘都是连接在南桥上。在由南桥将他们汇总到北桥上。

  北桥

  1.北桥左边CPU和cache:CPU负责所有控制和运算。

  2.北桥下面PCI总线

  3.北桥右边memory

  SMP和多核

  现在CPU已经达到物理极限,被4GHz所限制,于是,开始通过增加CPU数量来提高计算机速度。

  对称多核处理器:最常见的一种形式。每个CPU在系统中所处的地位和所发挥的功能是一样的,是相互对称的。但在处理程序时,我们并不能把他们分成若干个不相干的子问题,所以,使得多处理器速度实际提高的并没有理论上那么高。当对于相互独立的问题,多处理器就能最大效能的发挥威力了(比如:大型数据库,网络服务等)。

  对处理器由于造价比较昂贵,主要用于商用电脑上,对个人电脑,主要是多核处理器。

  多核处理器:其实际上是SMP的简化版,思想是将多个处理器合并在一起打包出售,他们之间共享比较昂贵的缓存部件,只保留了多个核心。在逻辑上看,它们和SMP完全相同。

1.3站得高,看得远

  系统软件:一般用于管理计算机本地的软件。

  主要分为两块:

  平台性的:操作系统内核,驱动程序,运行库。

  程序开发:编译器,汇编器,链接器。

  计算机系统软件体系结构采用一种层的架构。

  每个层次之间都需要相互通信,那么它们之间就有通信协议,我们将它称为接口,接口下层是提供者,定义接口。上层是使用者,使用接口实现所需功能。

  除了硬件和应用程序,其他的都是中间层,每个中间层都是对它下面的那层的包装和扩展。它们使得应用程序和硬件之间保持相对独立。

  从整个层次架构来看,开发工具与应用程序处于同一个层次,因为他们都使用同一个接口------操作系统应用程序编程接口。应用程序接口提供者是运行库,什么样的运行库提供什么样的接口。windows的运行库提供windows API,linux下的gliba库提供POSIX的API。

  运行库使用操作系统提供的系统调用接口。

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

  操作系统内核层对于硬件层来说是硬件接口的使用者,而硬件是接口的定义者。这种接口叫做硬件规格。

1.4操作系统做了什么

  操作系统的一个功能是提供抽象的接口,另外一个主要功能是管理硬件资源。

  一个计算机中的资源主要分CPU,存储器(包括内存和磁盘)和I/O设备。下面从这三个方面来看如何挖掘它们。

  1.4.1不要让CPU打盹

  多道程序:编译一个监控程序,当程序不需要使用CPU 时,将其它在等待CPU的程序启动。但它的弊端是不分轻重缓急,有时候一个交互操作可能要等待数分钟。

  改进后

  分时系统:每个CPU运行一段时间后,就主动让出给其他CPU使用。完整的操作系统雏形在此时开始出现。但当一个程序死机的时候,无法主动让出CPU,那么,整个系统都无法响应。

  目前操作系统采用的方式

  多任务系统:操作系统接管了所有的硬件资源,并且本身运行在一个受硬件保护的级别。所有的应用都以进程的方式运行在比操作系统更低的级别,每个进程都有自己独立的地址空间,使得进程之间的地址空间相互隔离。CPU由操作系统进行统一分配,每个进程根据进程优先级的高低都有机会获得CPU,但如果运行超过一段时间,CPU会将资源分配给其他进程,这种CPU分配方式是抢占式。如果操作系统分配每个进程的时间很短,就会造成很多进程都在同时运行的假象,即所谓的宏观并行,微观串行。

  设备驱动

  操作系统作为硬件层的上层,它是对硬件的管理和抽象。

  对于操作系统上面的运行库和应用程序来说,他们只希望看到一个统一的硬件访问模式。

  当成熟的操作系统出现后,硬件逐渐成了抽象的概念。在UNIX中,硬件设备的访问形式和访问普通的文件形式一样。在windows系统中,图形硬件被抽象成GDI,声音和多媒体设备被抽象成DirectX对象,磁盘被抽象成普通文件系统。

  这些繁琐的硬件细节全都交给了操作系统中的硬件驱动。

  文件系统管理这磁盘的存储方式。

  磁盘的结构:一个硬盘往往有多个盘片,每个盘片分两面,每面按照同心圆划分为若干磁道,每个磁道划分为若干扇区,每个扇区一般512字节。

  LBA:整个硬盘中所有扇区从0开始编号,一直到最后一个扇区,这个扇区编号叫做逻辑扇区号。

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

1.5内存不够怎么办

  在早期的计算机中,程序是直接运行在物理内存中,程序所访问的都是物理地址。

  那么如何将计算机有限的地址分配给多个程序使用。

  直接按物理内存分配将产生很多问题:

  地址空间不隔离:所有的程序都直接访问物理地址,导致程序使用的物理地址不是相互隔离的,恶意的程序很容易篡改其他程序的内存数据。

  内存使用效率低:由于没有有效的内存管理机制,通常一个程序执行的时候,监控程序要将整个程序读入。内存不够的时候,需要先将内存中的程序读出,保存在硬盘上,才能将需要运行的程序读入。这样会使得整个过程有大量数据换入换出。

  程序运行地址不确定:每次程序运行都需要内存分配一块足够大的内存空间,使得这个地址是不确定的。但在程序编写的时候,他访问的数据和指令跳转的目标地址都是固定的,这就涉及到了程序的重定向问题。

  一种解决办法:

  中间层:使用一种简洁的地址访问方法,我们把程序给出的地址看作一种虚拟地址。虚拟地址是物理地址的映射,只要处理好这个过程,就可以起到隔离的作用。

  1.5.1关于隔离

  普通的程序它只需要一个简单的执行环境,一个单一的地址空间,有自己的CPU。

  地址空间比较抽象,如果把它想象成一个数组,每一个数组是一字节,数组大小就是地址空间的长度,那么32位的地址空间大小就是2^32=4294967296字节,即4G,地址空间有效位是0x0000000~0xFFFFFFFF。

  地址空间分为两种:

  物理空间:就是物理内存。32位的机器,地址线就有32条,物理空间4G,但如果值装有512M的内存,那么实际有效的空间地址就是0x00000000~0x1FFFFFFF,其他部分都是无效的。

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

  1.5.2分段

  基本思路:把一段与程序所需要的内存空间大小的虚拟空间映射到某个地址空间。虚拟空间的每个字节对应物理空间的每个字节。这个映射过程由软件来完成。

  分段的方式可以解决之前的第一个(地址空间不隔离)和第三个问题(程序运行地址不确定)。

  第二个问题内存使用效率问题依旧没有解决。

  1.5.3分页

  基本方法:把地址空间人为的分为固定大小的页,每一页大小由硬件决定或硬件支持多种大小的页,由操作系统决定页的大小。

  目前几乎所有的PC上的操作系统都是4KB大小的页。

  我们把进程的虚拟地址空间按页分割,把常用的数据和代码页转载到内存中,把不常用的代码和数据保存到磁盘里,当需要的时候从磁盘取出来。

  虚拟空间的页被映射到虚拟页,物理内存中页叫做物理页,把磁盘中的页叫做磁盘页。虚拟空间的 有的页被映射到同一个物理页,这样就可以实现内存共享。

  当进程需要一个页时,这个页是磁盘页时,硬件会捕捉到这个消息,就是所谓的页错误,然后操作系统接管进程,负责从磁盘中读取内容装入内存中,然后再将内存和这个页建立映射关系。

  保护也是页映射的目的之一,每个页都可以设置权限属性,只有操作系统可以修改这些属性,这样操作系统就可以保护自己保护进程。

  虚拟存储的实现需要依靠硬件实现支持,所有硬件都采用一个叫MMU的部件来进行页映射。CPU发出虚拟地址经过MMU转换成物理地址,MMU一般都集成在CPU内部。

1.6众人拾柴火焰高

  1.6.1线程基础

  多线程现在作为实现软件并发执行的一个重要方法,具有越来越重的地位。

  什么是线程:线程有时候被称为轻量级的进程,是程序执行流的最小单元。构成:线程ID,当前指令指针,寄存器集合,堆栈空间(代码段,数据段,堆),进程级的资源(打开文件和信号)。

  多线程可以互不干扰的并发执行,并共享进程的全局变量和堆的数据。

  使用多线程的原因有如下几点:

  某个操作可能会陷入长时间等待,等待的线程会进入睡眠状态,无法继续执行。

  某个操作会消耗大量的时间,如果只有一个线程,程序和用户之间的交互会中断。

  程序逻辑本身就要求并发操作。

  多CPU或多核计算机,本身具备同时执行多个线程的能力。

  相对于多进程应用,多线程在数据共享方面效率要高很多。

  线程的访问权限

  线程的访问非常自由,它可以访问进程内存里所有数据,包括其他线程的堆栈(如果知道地址的话,情况很少见)。

  线程自己的私用存储空间:栈,线程局部存储;某些操作系统为线程提供私用空间,但容量有限,寄存器;执行流的基本数据,为线程私用。

  线程调度与优先级:不论是在多处理器还是单处理器上,线程都是并发的。线程数量小于处理器数量时,是真正并发的。单处理器下,并发是模拟的,操作系统会让这些多线程程序轮流执行,每次都只执行一小段时间,这就称为线程调度。

  1.6.2线程安全

  1.6.3多线程的内部情况

原文地址:https://www.cnblogs.com/jhmu0613/p/7354200.html