我们将处理器的指令集架构和处理器的微体系结构区分开来:指令集架构描述的是每条机器代码效果,而微体系结构描述的是处理器实际上是如何实现的。
运行程序
当我们在键盘上输入字符串./hello后,shell程序将字符逐一读入寄存器,再把它放到内存中。
利用直接存储器存取技术,数据可以不通过处理器而直接从磁盘到达内存。
一旦目标文件hello中的代码和数据被加载到主存,处理器就开始执行hello程序的main程序中的机器语言指令。这些指令将"hello,world\n"字符串中的字节从主存复制到寄存器文件,再从寄存器文件中复制到显示设备适配器,最终显示在屏幕上.
根据机械原理,较大的存储设备要比较小的存储设备运行的慢,而快速设备的造价远高于同类的低速设备。比如说,一个典型系统上磁盘可能要比内存大1000倍,但是对处理器而言,从磁盘上取一个字的时间开销要比从内存中读取的开销大1000万倍。
类似的,一个典型的寄存器文件只存储几百字节的信息,而主存可存放几十亿的字节,然而,处理器从寄存器中读数据比内存中几乎要快100倍。
存储器层次结构的思想是上一层的存储器作为低一层存储器的高速缓存。因此寄存器是一级缓存的高速缓存,一级缓存是二级缓存的高速缓存,二级缓存是三级缓存的高速缓存,三级缓存是内存的高速缓存,而内存又是磁盘的高速缓存。
所有应用程序对硬件的操作尝试都必须通过操作系统。
操作系统有两个基本的功能
1.防止硬件被失控的程序滥用
2.向应用程序提供简单一致的机制来控制复杂而又通常大不相同的低级硬件设备。
操作系统通过几个基本的抽象来实现这两个功能
文件是对IO设备的抽象,虚拟内存是对主存和IO设备的抽象,进程刚是对处理器 主存和IO设备的抽象。
像hello这样的程序在现代系统上运行时,操作系统会提供一种抽象,就好像系统上只有这个程序在运行。程序看上去是独立的使用处理器主存和IO设备。
处理器看上去就像在不间断地一条接一条的执行程序的指令,即该程序的代码和数据是系统内存中唯一的对象。这些假象是通过进行的概念来实现的,进程是计算机科学中最重要和最成功的概念之一。
进行是操作系统对一个正在运行程序的一种抽象。在一个系统上可以同时运行多个进程,而每个进程都好像独占使用硬件。
无论是单核还是多核,一个CPU看上去都像是在并发的执行多个程序,这个通过处理器在进程间切换来实现的。操作系统实现这种交错的机制称为上下文切换。
虚拟内存
虚拟内存是一个抽象概念,它为每个进程提供了一个假象,即每个进程都在独占的使用主存。每个程序看到的内存都是一致的,称为虚拟地址空间。
在Linux中,地址空间最上面的区域是保留给操作系统中的代码和数据的,这对所有进程来说都是一样的。地址空间的底部区域存放用户进程中定义的代码和数据。请注意地址是从下往上增长的。
程序代码和数据 :对所有的进程来说,代码是从同一固定地址开始,紧接着的是和Car全局变量对应的数据位置。代码区和数据区是直接按照可执行目标文件的内容初始化的。
堆代码和数据区后紧接着的是运行时堆。代码和数据区在进程一开始运行时就被指定了大小,与此不同,当调用malloc和free这样的C标准库函数时,可以在运行时动态的扩展和收缩。
共享库大约在地址空间中间部分是一块用来存放像C标准库和数学库这样的共享库的代码和数据的区域。共享库的概念非常强大,也相当难懂。
栈位于用户虚拟地址空间顶部的是用户栈,编译器用它来实现函数的调用。和堆一样,用户栈在程序执行期间可以动态地扩展和收缩。特别地
信号量
进化版的互斥锁
由于互斥锁的粒度比较大,如果我们希望在多个线程间对某一对象的部分数据进行共享,
使用互斥锁是没有办法实现的,只能将整个数据对象锁住。这样虽然达到了多线程操作共享数据时保证数据准确性的目的,却无形中导致线程的并发性下降。线程从并行处理变成了串行处理。与直接使用单进程无异。
信号量是相对折中的一种处理方式,既能保证同步,数据不混乱,有可以提高线程并发.