2017/05/08学习笔记

我们将处理器的指令集架构和处理器的微体系结构区分开来:指令集架构描述的是每条机器代码效果,而微体系结构描述的是处理器实际上是如何实现的。

运行程序

当我们在键盘上输入字符串./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标准库和数学库这样的共享库的代码和数据的区域。共享库的概念非常强大,也相当难懂。
位于用户虚拟地址空间顶部的是用户栈,编译器用它来实现函数的调用。和堆一样,用户栈在程序执行期间可以动态地扩展和收缩。特别地

信号量

进化版的互斥锁
由于互斥锁的粒度比较大,如果我们希望在多个线程间对某一对象的部分数据进行共享,
使用互斥锁是没有办法实现的,只能将整个数据对象锁住。这样虽然达到了多线程操作共享数据时保证数据准确性的目的,却无形中导致线程的并发性下降。线程从并行处理变成了串行处理。与直接使用单进程无异。
信号量是相对折中的一种处理方式,既能保证同步,数据不混乱,有可以提高线程并发.

信号和信号量完全没关系

时间: 2024-12-09 10:28:20

2017/05/08学习笔记的相关文章

2017/03/08学习笔记

结构体深copy和浅copy问题 编译器的=号操作,只会把结构体中指针变量的值copy,但不会重新开辟内存空间.//出现浅copy出现的场景是,结构体里面有指针成员的时候.如果需要执行深copy,需要手动显示分配内存,然后手动copy指针成员所执行的数据. 结构体偏移量定义下来,则结构体中的成员 内存布局就定义下来了,可以通过成员地址去求结构体的内存地址 文件操作 文件的分类按文件的逻辑结构分为记录文件:由具有一定结构的记录组成(定长和不定长)流式文件:由一个个字符(字节)数据顺序组成.按存储介

Python学习笔记-2017.5.4thon学习笔记-2017.8.08

#random模块 import random print(random.random())#0到1之间的随机数 print(random.randint(1,10))#从1到10随机 print(random.randrange(1,10))#从1到9随机,不包括10 print(random.choice([1,2,3,4,5]))#内容可以是字符串,元组,列表等对象 print(random.sample("jack", 2))#在指定的对象中选择两个,当然,也可以是其他个数 p

2017.04 vue学习笔记---08表单控件绑定---基础用绑定value

<!DOCTYPE html><html lang="en"><head> <meta charset="UTF-8"> <title>Title</title> <style> div{ margin-bottom: 30px; } </style> <script src="js/vue.js"></script> <

2017.04 vue学习笔记---08表单控件绑定---基础用法

<!DOCTYPE html><html lang="en"><head> <meta charset="UTF-8"> <title>Title</title> <style> div{ margin-bottom: 30px; } </style> <script src="js/vue.js"></script> <

Python学习笔记-2017.5.4thon学习笔记-2017.5.14

Python学习过程中的笔记,只做自己参考使用: lambda函数,匿名函数,当我们使用一个函数并且使用完成就删除时,可以使用匿名函数,比如f等于xyz三个之和: f = lambda x,y,z:x+y+z 生成器和迭代器: 生成器,我们常用的列表一般有两种方式生成,例如: 1.直接写出列表 a = [1,2,3,4,5,6,7,8,9] 2.通过列表生成式生成列表 a = [i*i for i in range(10)] 上述两种列表是我们常用的列表方式,调取方便,随便增删改查取值,但是有可

2017/03/31学习笔记

双向链表 单向链表的节点都只有一个指向下一个节点的指针单向链表的数据元素无法直接访问其前驱元素逆序访问单向链表中的元素时极其耗时的操作双向链表在单向链表的基础上增加了指向前驱的指针功能上双向链表可以完全取代单向链表的使用 栈是一种特殊的线性表 栈仅能在线性表的一端进行操作栈顶:允许操作的一端栈底:不允许操作的一端首先它是一个线性表,也就是说,栈元素具有线性关系,即前驱后继关系.只不过它是一种特殊的线性表.定义中说是在线性表的表尾进行插入和删除操作,这里表尾是指栈顶,而不是栈底.他的特殊之处就在于

2017/03/27学习笔记

程序的输入是指从输入文件讲数据传送给程序,程序的输出是指从程序将数据传送输出文件.C++输入输出包含以下三方面内容:对系统指定标准设备的输入和输出.即从键盘输入数据,输出到显示器.这种输入输出称为标准输入输出,简称标准IO.以外出磁盘文件为对象进行输入输出,即从磁盘文件输入数据,将数据输出到文件.以外存为对象的输入输出称为文件的输入输出,简称文件IO.度内存中指定的空间进行输入输出,通常指定一个字符串数组作为储存空间(实际上可以利用该空间储存任何信息).这种输入输出称为字符串输入输出,简称串IO

2017/04/27学习笔记

fork创建子进程后执行的是和父进程相同的程序(但有可能执行不同的代码分支),子进程往往要调用一种exec函数执行另一个程序.当进程调用一个exec函数时,该进程的用户空间和数据完全被新程序替换,从新程序的启动例程开始执行.调用exec并不创建新进程,所以调用exec前后该进程ID不变.将当前进程的.text .data替换为所要加载程序的.text .data,然后让进程从新的.text第一条指令开始执行,但进程ID不变,换核不换壳. int execl();int execlp();int

2017/03/24学习笔记

类型转换 C语言中的强制类型转换很简单,不管什么类型的转换都是TYPE b=(TYPE)a; C++中类型转换提供了4种类型转换操作符来应对不同场合的应用.static_cast 静态转换.如int转换成charreinterpreter_cast 重新解释类型dynamic_cast 命名上理解是动态类型转换.如子类和父类之间的多态类型转换 (父类转子类,向下转型)const_cast 字面理解就是去const属性. 4种类型转换格式TYPE b=static_cast<TYPE>(a);