组成原理:
这门学科告诉你什么是计算机。 首先,我们可以把计算机分解成最原始的部件——晶体管。晶体管是一种半导体材料,其最重要的作用就是半导:可以通过电流的变化,实现电路的切换。
晶体管只有两种状态,高电平和低电平,用来表示逻辑上的0和1, 晶体管通过不同的组合形成大的输入输出元件,这些元件再通过组合形成逻辑电路,这就说我们说的运算基础,逻辑电路再组合就形成运算电路,运算电路集成到一起形成CPU,再配合时钟,就是我们所说的计算!而通过晶体管的电位差不同,就可以体现"二进制数据",即0和1。再加上电容和电阻,就能把这种二进制数据临时保存起来。
综合这些特性,人们发现把晶体管用作精密的数学计算,可以极大的提高运算的效率。比如我有2个电容,分别是充满电和没有电,对他们同时释放电信号,电容就会把其中的电子放出来,经过特定的逻辑电路,如与门,得到了0的结果。要计算1+1,实际上也是类似的原理。我先设计一个加法电路,把若干电容组合成的"数字"流过这个电路,把结果存入目标电容,就得到了结果。大规模的复杂运算以此类推。
最早期的计算机真的就是用许多结晶体管实现的复杂电路结构,通过控制输入电流得到希望的输出结果。后来人们发现,这种计算可以用某些形式抽象成多种指令,不用针对每次计算设计复杂的电路,只要调用指令就可以实现任何一种计算组合,于是就有了CPU
算术逻辑单元 ALU
大部分ALU都可以完成以下运算∶ 整数算术运算(加、减,有时还包括乘和除,不过成本较高) 位逻辑运算(与、或、非、异或) 移位运算(将一个字向左或向右移位或浮动特定位,而无符号延伸),移位可被认为是乘以2或除以2。
只有cpu,每次都要自己配置输入信号,实在太痛苦,就做了纸带输入给计算机。后来又发现纸带还是很麻烦,
1.费纸
2.容易破
于是发明了输入终端和对应的存储设备。后来又发现很多数据要临时保存起来,供连续计算使用,于是发明了内存。再后来pc的发展经历了无数次的变革,让计算机一步步到了今天的地步,也就是你现在看到的这样。
操作系统
综上所述,计算机发展到一定程度,什么东西都靠人工也未免太累了。 比如通过输入设备组织指令给cpu去计算,你希望能够找一个快速的输入设备(比如键盘),在能看到结果的地方输入(比如屏幕),然后再用很方便的方式提交给cpu(比如按键或者指令),让cpu去算好了,再把结果展示出来(比如屏幕)。 理想很美好,但是这么复杂的流程,人工管理起来不还是很麻烦吗?除非我构造一个设备,把这些所有设备都管理起来,于是主板就诞生了。
主板一般为矩形电路板,上面安装了组成计算机的主要电路系统,一般有BIOS芯片、I/O控制芯片、键盘和面板控制开关接口、指示灯插接件、扩充插槽、主板及插卡的直流电源供电接插件等元件 .
bios,其实,它是一组固化到计算机内主板上一个ROM芯片上的程序,它保存着计算机最重要的基本输入输出的程序、开机后自检程序和系统自启动程序,它可从CMOS中读写系统设置的具体信息。 其主要功能是为计算机提供最底层的、最直接的硬件设置和控制。此外,BIOS还向作业系统提供一些系统参数。系统硬件的变化是由BIOS隐藏,程序使用BIOS功能而不是直接控制硬件。现代作业系统会忽略BIOS提供的抽象层并直接控制硬件组件。
现在主板解决了我们大量的问题,但是我发觉我的需求还远远不够! 我希望我写过的程序能在任何一台机上运行。(可移植性) 我希望我能边听音乐边干活——即同一时间可以运行多个程序。() 我希望别人写的傻×东西不要影响到我的工作——即多任务控制。 我希望计算机里面的各种资源都能得到良好的组织,更快的访问。 我希望我的用户界面更好看,使用更方便,功能更强大! 我是个小白用户,啥都不懂,别跟我扯这些有的没的,我就想随便操作两下就能达到我想要的! 如果这些需求全部都做在主板bios里面,那将是一场灾难!除非bios经过极大的调整和改动,划分出一大块区域存放操作系统,并且完成复杂的体系结构改革。 计算机发展到这种程度,早就已经有很多的机构和厂商介入其中,试图从中渔利。他们当然不会求着计算机标准委员会和主板生产厂商去做所谓的主板改革,而是编写自己的程序——操作系统,来解决这些所有的问题。
而操作系统问世之后,一方面接管了主板对于系统资源的管理,加入了自己的中间层——驱动程序,另一方面又充分发挥了人机交互的接口——gui界面,成为了计算机必不可少的组成部分。 操作系统通过bios引导,即作为应用程序开始运行。我们知道程序的本质上就是在cpu上运行种种指令,比如操作系统需要把硬盘上的模块放入内存,实际上就是运行了一系列复杂的cpu指令,cpu指令通过主板bus(实际上就是传递指令的电路)发送指令给硬盘(比如从哪个扇区偏移多少读多少数据),硬盘再通过芯片组转动磁头,把数据读到缓存中,完成后给cpu发送一个信号(即中断),cpu收到这个信号,就在寄存器中寻址该信号对应的地址(即我们说的中断向量表),运行该地址中的指令,发现该指令是发送拷贝指令给主板芯片组,主板就会在cpu的指导下不断的发送信号,告诉硬盘缓存放电,再把接收的电信号存到指定的内存位置去,如此反复,直到完成cpu的一系列指令为止。 操作系统说白了,就是这样通过种种cpu指令,实现自身的所有功能。 当然这些指令也不是一条条写进去的,而是通过编程语言完成人类较容易识别的逻辑,然后再通过编译器把这些逻辑翻译成cpu指令,这就涉及编译原理的东西了。
既然操作系统对硬件的访问都是通过cpu指令来完成的,那为什么大家都感觉是操作掌管了硬件呢?这就涉及操作系统最本质的功能之一:对系统资源的管控了。 我们运行的所有程序,实际上都是操作系统帮我们运行的。操作系统背后进行了很多的工作,如虚拟地址空间的分配,cpu分时调度,硬件中断信号的响应等。这样对于硬件资源的访问,也是通过操作系统安排的。比如操作系统会通过把短时间内硬盘读写合并成顺序的方式,以提高磁头的利用率,降低磁头转向的时间。再比如对内存地址的访问也是由操作系统管控的,某个程序中的内存地址具体落到内存条的哪个位置,还是硬盘中的虚拟内存,就看操作系统的心情了。
至此,操作系统和硬件的交互也介绍的差不多了,更详细的东西建议参考操作系统相关的书籍吧,比如《深入理解计算机系统》,《linux内核设计与实现》,《unix环境高级编程》之类的。
构成,重点cpu的构成,寄存器,缓存,内存,磁盘
操作系统最核心的概念:进程
-
操作系统必须交替执行多个进程,在合理的响应时间范围内使处理器的利用率最大
-
操作系统必须按照特定的策略给进程分配资源,同时避免死锁
定义:正在执行的程序
具有以下特征的活动单元:一组指令序列的执行,一个当前状态和相关的系统资源集
进程控制块
进程的执行
进程的状态
(1)运行:当一个进程在处理机上运行时,则称该进程处于运行状态。处于此状态的进程的数目小于等于处理器的数目,对于单处理机系统,处于运行状态的进程只有一个。在没有其他进程可以执行时(如所有进程都在阻塞状态),通常会自动执行系统的空闲进程。
(2)就绪:当一个进程获得了除处理机以外的一切所需资源,一旦得到处理机即可运行,则称此进程处于就绪状态。就绪进程可以按多个优先级来划分队列。例如,当一个进程由于时间片用完而进入就绪状态时,排入低优先级队列;当进程由I/O操作完成而进入就绪状态时,排入高优先级队列。
(3)阻塞:也称为等待或睡眠状态,一个进程正在等待某一事件发生(例如请求I/O而等待I/O完成等)而暂时停止运行,这时即使把处理机分配给进程也无法运行,故称该进程处于阻塞状态。
-
三状态图
-
五状态图
-
七状态图
存储器知识
cache通常也分为多级。L1 cache在CPU芯片内部,而L2 cache在主板上。为了支持指令流水,L1 cache将指令、数据分开;L2则是指令、数据存储在一起的。
-
为啥要有线程
首先来一句概括的总论:进程和线程都是一个时间段的描述,是CPU工作时间段的描述。
下面细说背景: CPU+RAM+各种资源(比如显卡,光驱,键盘,GPS, 等等外设)构成我们的电脑,但是电脑的运行,实际就是CPU和相关寄存器以及RAM之间的事情。
一个最最基础的事实:CPU太快,太快,太快了,寄存器仅仅能够追的上他的脚步,RAM和别的挂在各总线上的设备完全是望其项背。那当多个任务要执行的时候怎么办呢?轮流着来?或者谁优先级高谁来?不管怎么样的策略,一句话就是在CPU看来就是轮流着来。
一个必须知道的事实:执行一段程序代码,实现一个功能的过程介绍 ,当得到CPU的时候,相关的资源必须也已经就位,就是显卡啊,GPS啊什么的必须就位,然后CPU开始执行。这里除了CPU以外所有的就构成了这个程序的执行环境,也就是我们所定义的程序上下文。当这个程序执行完了,或者分配给他的CPU执行时间用完了,那它就要被切换出去,等待下一次CPU的临幸。在被切换出去的最后一步工作就是保存程序上下文,因为这个是下次他被CPU临幸的运行环境,必须保存。
串联起来的事实:前面讲过在CPU看来所有的任务都是一个一个的轮流执行的,具体的轮流方法就是:进程和线程,两个名词不过是对应的CPU时间段的描述,名词就是这样的功能。
线程是什么呢? 进程的颗粒度太大,每次都要有上下的调入,保存,调出。如果我们把进程比喻为一个运行在电脑上的软件,那么一个软件的执行不可能是一条逻辑执行的,必定有多个分支和多个程序段,就好比要实现程序A,实际分成 a,b,c等多个块组合而成。那么这里具体的执行就可能变成:
程序A得到CPU =》CPU加载上下文,开始执行程序A的a小段,然后执行A的b小段,然后再执行A的c小段,最后CPU保存A的上下文。
这里a,b,c的执行是共享了A的上下文,CPU在执行的时候没有进行上下文切换的。这**里的a,b,c就是线程,也就是说线程是共享了进程的上下文环境,的更为细小的CPU时间段。
到此全文结束,再一个总结: **进程和线程都是一个时间段的描述,是CPU工作时间段的描述,不过是颗粒大小不同。
多道程序设计技术:管理单处理器系统中的多个进程
并发问题
void echo(){
chin = getchar();
chout=chin;
putchar(chout);
}
进程间资源竞争
一个进程的结构与其他进程无关
两个或多个进程在它们执行过程中需要访问一个资源,每个进程并不知道其他进程的存在,并且每个进程也不受其他进程的影响
临界资源
简单一点,就是为了争夺I/O设备,存储器,处理器事件和时钟等资源
进程间通过共享合作
一个进程的结构可能依赖于其他进程获得的信息
例如
P1:
a=a+1;
b=b+1;
P2:
b=b+2;
a=a+2;
读脏数据
进程间通过通信合作
互斥
死锁
死锁三个必要条件
-
互斥
上锁,信号量
-
占用且等待
-
不可抢占
加上第四个,就是充分条件
循环等待
死锁预防
死锁避免
死锁检测
恢复
饥饿
哲学家就餐问题
如果我们不加以限制,在同一时刻,哲学家都饿了,同时拿起左边的筷子,等待右边的筷子,然后,就死锁了!
方法1:规定在拿到左侧的筷子后,先检查右面的筷子是否可用。如果不可用,则先放下左侧筷子, 等一段时间再重复整个过程。
但想想,这种,还是有些问题,可能在某一瞬间,所有哲学家都开始这个算法,拿起其左筷,发现右筷不可用,又都放下左筷,等了一会,又同时拿起左筷,如此这样永远重复下去,这种,所有程序都在不停的运行,但都无法取得进展,就叫做“饥饿”
将方法1中等一段时间,改成等一段随机时间,互锁的可能性就小多了,事情就可以继续了,虽然可能觉得随机时间不太完美,但是这是一个很好的解决方法,例如,以太网中,如果两天计算机同时发送包,发生了碰撞,那么计算机会随机等待一段时间后在尝试
读者-写者问题
-
调度
-
文件
-
I/O