概述
生产者/消费者问题
系统中有一组生产者进程 和 一组消费者进程, 生产者每次生产一个产品(数据)放入缓冲区,消费中每次从缓冲区中取出一个产品使用(从缓冲区取一个数据处理)。
- 缓冲区满时,生产者必须等待
- 缓冲区空时,消费者必须等待
- 缓冲区为临界资源,必须互斥地访问
semaphore mutex = 1; -> 互斥信号量,实现对缓冲区的互斥访问
semaphore empty = n; -> 同步信号量,标识空闲缓冲区的数量
semaphore full = 0; -> 同步信号量,标识产品数量,也即非空缓冲区数量
Producer(){
while(1){
生产1个产品;
P(empty); <- 消耗1空闲buffer
P(mutex);
将产品放入缓冲区;
V(mutex);
V(full); <- 增加1个产品
}
}
Consumer(){
while(1){
生产1个产品;
P(full); <- 消耗1个产品
P(mutex);
从缓冲区取出一个产品;
V(mutex);
使用产品; <- 增加1个产品
}
}
多生产者-多消费者
在多生产者-多消费者问题中,如果缓冲区大于1,需要设置一个互斥信号量来保证互斥地访问缓冲区,否则有可能导致多生产者同时访问一个缓冲区单位造成数据覆盖地问题。内存
程序在执行前需要先加载到内存才能被CPU处理
- 内存地址从0开始,每个地址对应一个存储单元
- 如果计算机按字节编址,则每个存储单元大小为1字节,即8个二进制位。
- 如果字长为16位的计算机按字编制,则每个存储单元大小为1个字,每个字的大小为16个二进制位
判断存储单元的大小要看计算机是按字节编址还是按字编址的,
如果是按字编址,还要看每个字长是多少位,如32位计算机一个字长位32位
从写程序到运行:
过程:如上图所示,首先编译器会将我们写的源代码进行编译形成目标模块(.o,机器语言),然后由连接程序将目标文件以及所需的库链接在一起,形成一个完整的装入模块,这个过程使用的都是逻辑地址。最后将这个模块装载进内存运行。装入的三种方式:绝对装入、静态重定位、动态重定位
- 绝对装入:如果在编译时知道程序将放到内存中的哪个位置,编译程序将产生绝对地址的目标代码 ,装入程序按照装入模块中的地址将程序和数据装入内存
- 静态重定位:又称为 可重定位装入。编译、链接后的装入模块的地址均从0开始,指令中数据存放的地址都是相对于起始地址而言的逻辑地址,可根据内存的当前情况将模块装入内存适当位置,装入时对内存地址进行重定位,将逻辑地址变为物理地址。静态重定位的特点是:在作业装入内存时,必须分配其全部的内存空间,如果内存不够,则不能装入。作业一旦进入内存后,运行期间不能移动,也不能再申请内存空间。地址转换是在装入时一次完成的。
- 动态重定位:编译后形成的目标文件依然是逻辑地址,装入时依然保持使用逻辑地址。地址的转换等到程序执行时进行。
利用一个重定位寄存器,该寄存器存放装入模块的起始地址,每次CPU从内存读取数据的时候与该地址相加得到目标地址。这样允许程序在内存中移动(只需要更改重定位寄存器)。
链接的三种方式:静态链接、装入时动态链接、运行时动态链接
- 静态链接:程序执行前将各目标文件链接成一个完整的可执行文件装入模块
- 装入时动态链接:目标文件装入内存时,边装入边链接
- 运行时动态链接:程序执行时需要目标文件时才对它进行动态链接。
内存管理
内存空间的分配与回收
- 连续分配管理方式与非连续分配管理方式——连续分配:指为用户进程分配的必须是连续的内存空间
- 连续分配管理方式又分为:单一连续分配、固定连续分配、动态分区分配。
非连续分配管理方式又分为:基本分页存储管理、基本分段存储管理、段页式存储管理。 -
- 单一连续分配:内存分为系统区和用户区,用户区独占整个用户空间。
优点:实现简单,无外部碎片(即内存中某些空间分区太小而难以利用)。
缺点:只能用于单用户,单任务的操作系统中,有内部碎片(即分配给进程的内存,有部分没用上)。
- 单一连续分配:内存分为系统区和用户区,用户区独占整个用户空间。
-
- 固定分区分配:将用户空间分为若干固定大小分区,各分区大小相等/不相等。
操作系统需要建立一个数据结构:分区说明表,用来分配与回收各个分区
- 固定分区分配:将用户空间分为若干固定大小分区,各分区大小相等/不相等。
-
- 动态分区分配:不会预先划分分区,而是在进程装入内存时,根据进程的大小动态地建立分区,使分区大小正好适合进程的需要。
-
- 基本分页存储管理类:将内存空间分为一个个大小相同的分区,每个分区就是一个页框,或称为“页帧”,每个页框有个号码,从0开始; 然后将用户进程的地址空间也分为与页框大小相等的一个区域,称为“页”或“页面”,页号也是从0开始
操作系统以页框为单位为进程分配内存空间,进程每个页被放入相应的页框。
会有一个页表对这些进行管理
- 基本分页存储管理类:将内存空间分为一个个大小相同的分区,每个分区就是一个页框,或称为“页帧”,每个页框有个号码,从0开始; 然后将用户进程的地址空间也分为与页框大小相等的一个区域,称为“页”或“页面”,页号也是从0开始
-
- 基本分段存储:进程的地址空间按照程序自身的逻辑关系可以分为若干个段,每个段都有一个段名,每段从0开始编址。
如:对某个进程A,0号段为main() 函数,段名为MAIN,1号段为某个子函数,2号段保存全局变量…
内存分配以段为单位,每个段在内存中占据连续空间,但各段之间可以不相邻。
各个段由段表(段映射表)进行管理
- 基本分段存储:进程的地址空间按照程序自身的逻辑关系可以分为若干个段,每个段都有一个段名,每段从0开始编址。
内存空间的扩充
- 覆盖技术:解决程序大小超过物理内存总和的问题
覆盖技术思想:将程序分为多个段,常用段则常驻内存,不常用的段在需要时调入内存。内存中分为一个“固定区”和若干个“覆盖区”。固定区存放需要常驻的代码,如main()函数,覆盖区存放不需要常驻内存的代码。
缺点:需要由程序员声明覆盖层次。 - 交换技术:内存不够时,系统将内存中某些进程暂时换出外存(如一些阻塞的进程、优先级较低的进程,但是PCB会常驻内存),把外存中已具备运行条件的进程换入内存。进程这样在内存与磁盘之间动态调度。
地址转换
内存保护
防止进程访问不该访问的地址
- 方法一:在CPU中设置一对上、下限寄存器:进程的指令在访问某个地址时,由CPU检查其是否越界
- 方法二:采用重定位寄存器和界地址寄存器(或也可称为:基址寄存器和限长寄存器),基址寄存器存放进程的起始物理地址,限长寄存器存放进程的最大逻辑地址,由CPU进行越界检查。
虚拟内存
局部性原理:时间局部性、空间局部性
- 时间局部性:某条刚被访问的指令有可能很快再次被访问,如循环语句
- 空间局部性:某个刚被访问的存储单元,其附近的存储单元很可能很快被访问,如数组
所谓虚拟内存,只是操作系统虚拟性的一个体现,实际的物理内存大小没变,只是在逻辑上扩充了。
在程序执行的过程中,当所访问的信息不在内存时,由操作系统负责将所需信息从外存调入内存。
若内存空间不够,则操作系统负责将内存中暂时用不到的信息换出到外存。
最后
以上就是典雅帅哥为你收集整理的操作系统笔记2生产者/消费者问题内存的全部内容,希望文章能够帮你解决操作系统笔记2生产者/消费者问题内存所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
发表评论 取消回复