程序员的自我修养笔记(一)

一..牵扯到“计算”这个概念的都可以成为计算机,我们研究的主要是兼容x86指令集的32位CPU个人计算机。

1.

早期:CPU和内存的频率差不多,连接在同一个总线上。 I/O设备效率低,为了协调I/O设备和总线之间的速度,所以有了I/O控制器

早期:CPU速率提升,内存跟不上CPU速度,内存和新产生的系统总线速率一致,CPU和系统总线进行通信。

中期:图形化操作系统的产生使慢速的I/O总线无法满足这个需求,产生了处理高速的北桥和处理低速的南桥芯片

后期:CPU的速率被制造工艺束缚,无法突破4GHZ的速率,人们开始增加CPU的数量(一个女人十个月生一个孩子,十个女人不能一个月生一个孩子),处理器共享比较贵的部件,保留多个核心,多核处理器由此诞生

2.系统软件体系结构:增加间接中间层

(1)平台性:操作系统内核,驱动程序,运行库,系统工具等

(2)用于程序开发的:编译器,链接器,汇编器等开发工具和开发库

每个层次之间需要通信,所以必须有通信协议,又名接口,接口下面的那层使接口的提供者(定义接口),接口上面是接口的使用者,他使用该接口来实现所需功能。(除了硬件和应用程序其他都可以被替换)

3.操作系统功能:(1)提供抽象的接口(2)管理硬件资源

4

(1)CPU最初只运行一个程序,当程序读写磁盘,CPU就空闲了,所以有了多道程序(这个程序暂时不用就给别的程序用)

(2)分时系统:每个程序运行一段时间将CPU让给别的程序

(3)多任务系统:CPU由操作系统统一分配,根据进程的优先级分配,如果运行超过一定时间,操作系统暂停该进程,并将CPU分给别人,这种分配方式叫抢占式

5.硬件被抽象成一系列概念(磁盘被抽象成普通文件系统),硬件驱动:驱动程序的开发工作由硬件生产商完成,操作系统的开发者为硬件生产商提供了一系列接口和框架,凡是按照这个开发的驱动程序都可以在操作系统上使用

6.内存的使用:有限的物理内存分配给多个程序使用

(1)地址空间不隔离(真实物理地址,恶意程序)(2)内存使用率低(没有有效的内存管理机制) (3)程序运行的地址不确定

解决上述问题,增加中间层,虚拟地址

(1)分段:把一段与程序所需要的内存空间大小的虚拟空间映射到某个地址空间(解决上述(1)(3))

(2) 分页:把地址空间人为的分成固定大小的页,硬件支持多种大小的页,由操作系统选择决定页的大小。

7.线程:程序执行流的最小单元,一个进程由一个到多个线程组成,各个线程之间共享程序的内存空间(代码段,数据段,堆等),及一些进程级的资源(打开文件和信号)

使用多线程的原因:

(1)某个操作可能会陷入长时间等待,等待的线程会进入睡眠状态,无继续执行,多线程可以有效利用等待的时间

(2)某个操作会消耗大量的时间,只有一个线程可能会中断用户和程序,多线程可以一个交互,一个计算

(3)多核计算机本身具备多线程能力

(4)程序逻辑本身就要求并发操作

(5)相对多进程应用,多线程在数据共享方面效率很高

线程私有存储空间:栈(一般情况) 线程局部存储  寄存器

线程调度:运行,就绪,等待,时间片轮转法,优先级调度,线程优先级(pthread)

I/O密集型线程:频繁等待的线程

CPU密集型线程:频繁计算的线程

防止饿死现象:调度系统逐渐提升等待时间过长的线程的优先级

时间片用完以后被操作系统强制剥夺了执行权力,进入就绪状态,这个过程叫抢占。

在不可抢占线程中,线程主动放弃执行:(1)线程试图等待某事件(2)线程主动放弃时间片

Linux将所有执行实体统称为任务

线程安全:多线程程序处于一个多变的环境中,可访问的全局变量和堆数据随时可能被别的线程改变,因此多线程在并发时数据的一致性很重要

解决方法:原子指令,锁

8.同步:为了避免多个线程同时读写同一个数据而产生不可预料的后果,我们需要将各个线程对同一个数据的访问同步

锁:每个线程在访问数据之前试图获取锁,并在访问结束之后释放锁,在锁已经被占用的时候试图获取锁时,线程会等待,直到锁重新可用。

二元信号量:只有两种状态,占用和非占用,适合只能被唯一一个线程独占访问的资源

信号量即多元信号量:一个初始值为N的信号量允许N个线程并发访问,线程访问资源时先获取信号量

互斥量:仅允许一个线程访问,同一个信号量可以被系统中一个线程获取后被另一个线程释放,而互斥量要求谁获取谁释放

临界区:把临界区锁的获取叫进入临界区,临界区锁的释放叫做离开临界区,作用域在本进程,其他进程无法获得该锁,其他性质和互斥量相同。

读写锁:两种获取方式:共享和独占

过度优化也会影响线程安全(详情见P54)

9.三种线程模型:

(1)一对一模型:一个用户使用的线程对应唯一一个内核使用的线程。这种并发是真正意义上的并发,一个线程的阻塞不会影响另一个线程

(2)多对一模型:将多个用户线程映射到一个内核线程上,线程之间的切换由用户代码来执行

好处:高效的上下文切换和几乎无限制的线程数量

坏处:一个用户线程阻塞,所有线程都无法执行

(3)多对多模型:将多个用户线程映射到少数但不止一个内核线程上,综合上面两种

猜你喜欢

转载自blog.csdn.net/m0_43407388/article/details/107989030