完整课程设计CSDN下载:https://download.csdn.net/download/eseszb/10503175
代码下载:https://download.csdn.net/download/eseszb/10506006
操作系统课程设计报告
题目: 进程同步实现—生产者和消费者的问题
学号:
姓名:
任课教师:
2017年12月
摘 要
本课程设计利用模拟用信号量机制实现生产者和消费者问题:通过用户控制取进程和放进程,反应生产者和消费者问题中所涉及的进程的同步与互斥。在理解和分析了生产者消费者问题的核心问题以及状态的本质涵义的前提下,对进程同步的实现在总体上进行了设计,包括在对算法分模块设计,并对各个模块的算法思想通过流程图表示,分块编写代码,并进行测试,最后进行程序的测试,在设计思路上严格按照软件工程的思想执行,确保了设计和实现的可行,可信。代码实现采用C++语言。
关键词:生产者、消费者、进程同步、临界资源、缓冲区
目录
第一章 绪论 1
1.1 课程设计的目的 1
1.2 课程设计的内容 1
1.3 相关知识 1
1.4章节安排 2
1.5 本章小结 3
第二章 生产者消费者问题的需求分析 4
2.1 环境需求 4
2.2 功能需求 4
2.3 性能需求 4
2.4 本章小结 5
第三章 实现进程同步的设计 6
3.1 总体设计 6
3.2 功能模块设计 6
3.3 本章小结 7
第四章 算法的实现 9
4.1 开发环境介绍 9
4.2 主要功能模块的实现 9
4.3 本章小结 16
第五章 测试及成果展示 17
5.1 测试环境 17
5.2 测试用例和结果 17
5.3 成果展示 25
5.4 本章小结 29
第六章 总结与展望 30
附录 31
参考文献 38
第一章 绪论
“操作系统”是计算机专业的核心专业课,“操作系统课程设计”是理解和巩固操作系统基本理论、原理和方法的重要实践环节。
通过实验模拟生产者和消费者之间的关系,了解并掌握他们之间的关系及其原理。由此增加对进程同步的问题的了解。具体如下:
1)掌握基本的同步互斥算法,理解生产者和消费者模型;
2)了解windows中多线程(多进程)的并发执行机制,线程(进程)间的同步和互斥;
3)学习使用windows中基本的同步对象,掌握相应的API。
本课程通过设计实现一个综合作业,加深对操作系统原理的理解,提高综合运用所学知识的能力,培养学生独立工作和解决问题的能力,取得设计与调试的实践经验,为今后进一步从事计算机系统软件和应用软件的分析、研制和开发打下良好的基础。
本次课程设计主要通过C++模拟信号量制中各个进程,及各进程之间的互斥、同步关系,来实现生产者和消费者问题。
生产者消费者问题(英语:Producer-consumer problem),也称有限缓冲问题(英语:Bounded-buffer problem),是一个多线程同步问题的经典案例。该问题描述了两个共享固定大小缓冲区的线程——即所谓的“生产者”和“消费者”——在实际运行时会发生的问题。生产者的主要作用是生成一定量的数据放到缓冲区中,然后重复此过程。与此同时,消费者也在缓冲区消耗这些数据。该问题的关键就是要保证生产者不会在缓冲区满时加入数据,消费者也不会在缓冲区中空时消耗数据。
要解决该问题,就必须让生产者在缓冲区满时休眠(要么干脆就放弃数据),等到下次消费者消耗缓冲区中的数据的时候,生产者才能被唤醒,开始往缓冲区添加数据。同样,也可以让消费者在缓冲区空时进入休眠,等到生产者往缓冲区添加数据之后,再唤醒消费者。如果解决方法不够完善,则容易出现死锁的情况。出现死锁时,两个线程都会陷入休眠,等待对方唤醒自己。该问题也能被推广到多个生产者和消费者的情形。
(1)生产者、消费者:两个共享固定大小缓冲区的线程
(2)进程间的同步:异步环境下的一组并发进程因直接制约而互相发送消息、进行互相合作、互相等待,使得各进程按一定的速度执行的过程。
(3)缓冲区:暂时置放输入或输出资料的内存
(4)临界资源:一次仅允许一个进程使用的资源。
本文的组织结构为:第一章为绪论,第二章需求分析内容,第三章是进程同步问题的实现,第四章是算法的具体实现,第五章是软件实现后的测试,包过测试用例和测试结果,第六章节为本次论文的总结,最后是附录为软件源代码和参考文献。
第一章绪论,主要是介绍本次课程设计的目的、内容等。
第二章需求分析,主要介绍算法应该实现的功能需求,以及算法应该改满足的性能要求。
第三章是算法的设计,本次实现进程同步
第四章是算法的实现,根据第三章的设计,画出每个模块的流程图,很据设计和流程图编程实现每一个模块的功能。
第五章是测试,主要是进行软件的测试,选择测试用例,看软件是否满足所有的需求分析。
第六章是总结,总结本次设计的结果,意义以及对未来的展望。
本章的主要是对于此次进程同步问题的背景、意义以及设计安排的进行概述,使读者能够大体了解本课程设计主要实现目标与构成要素,对于接下来的章节的论述有着系统导向作用。
第二章 生产者消费者问题的需求分析
2.1环境需求:
Windows7系统、Microsoft visual VC++ 6.0
2.2功能需求:
n 对于生产者进程:产生一个数据,当要送入缓冲区时,要检查缓冲区是否已满,若未满,则可将数据送入缓冲区,并通知消费者进程;否则,等待;
n 对于消费者进程:当它去取数据时,要看缓冲区中是否有数据可取,若有则取走一个数据,并通知生产者进程,否则,等待。
n 缓冲区是个临界资源,因此,诸进程对缓冲区的操作程序是一个共享临界区,所以,还有个互斥的问题。
2.3性能需求 :
1.生产者、消费者将会进行生产和消费动作,并显示当前的状态。
2.程序能够一直进行生产消费活动,直到人为结束(在本程序里为按下回车键)。
3.执行过程中不会出现争夺资源而中止。
2.4本章小结:
本章的主要是对于此次设计并且实现生产者消费者问题的需求进行分析,包括环境需求、功能需求和性能需求进行详细的分析,确定了此次设计并且实现生产者消费者问题的运行测试环境,以及设计并且生产者消费者问题的功能要求和性能要求,为后面的实现生产者消费者问题确定了明确的目标。
第三章 生产者消费者问题的设计
3.1 总体设计
利用模拟用信号量机制实现生产者和消费者问题:通过用户控制取进程和放进程,反应生产者和消费者问题中所涉及的进程的同步与互斥。
3.2 功能模块设计
3.2.1数据流程图:
1、生产者
2、消费者
3.2.2模块说明:
const unsigned short SIZE_OF_BUFFER = 10; //缓冲区长度
unsigned short ProductID = 0; //产品号
unsigned short ConsumeID = 0; //将被消耗的产品号
unsigned short in = 0; //产品进缓冲区时的缓冲区下标
unsigned short out = 0; //产品出缓冲区时的缓冲区下标
int g_buffer[SIZE_OF_BUFFER]; //缓冲区是个循环队列
bool g_continue = true; //控制程序结束
HANDLE g_hMutex; //用于线程间的互斥
HANDLE g_hFullSemaphore; //当缓冲区满时迫使生产者等待
HANDLE g_hEmptySemaphore; //当缓冲区空时迫使消费者等待
DWORD WINAPI Producer(LPVOID); //生产者线程
DWORD WINAPI Consumer(LPVOID); //消费者线程
3.3本章小结
本章主要讲述了生产者消费者问题的设计,包括生产者、消费者的数据流程图、以及一些模块说明。
第四章 算法的实现
1.window XP或window 7系统。
2. Microsoft visual VC++ 6.0
本课程设计利用模拟用信号量机制实现生产者和消费者问题,即在生产一个产品之前添加P1操作,在其后添加V1操作;在消费一个产品之前添加P2操作,在其后添加V2操作。
而本算法则用
WaitForSingleObject(g_hFullSemaphore,INFINITE);实现资源信号量的P操作,WaitForSingleObject(g_hMutex,INFINITE);实现互斥信号量的P操作,
ReleaseMutex(g_hMutex)实现互斥信号量的V操作,ReleaseSemaphore(g_hEmptySemaphore,1,NULL);实现资源信号量的V操作。
Take(); //从缓冲区中取出一个产品
Consume(); //消费一个产品
Produce(); //生产一个产品
Append(); //把新生产的产品放入缓冲区
4.2.1生产一个产品,输出其ID号
void Produce()
{
std::cout< std::cerr<<"生产一个产品: "<<++ProductID; std::cout< } 4.2.2把新生产的产品放入缓冲区 void Append() { std::cerr<<"把生产的产品送入缓冲区"; g_buffer[in]=ProductID; in=(in+1)%SIZE_OF_BUFFER; std::cerr< std::cout<<"缓冲区 产品 生产者/消费者"< //新产品放入缓冲区后,输出缓冲区当前的状态 for(int i=0;i { //输出缓冲区下标 if (i<10) std::cout<
else std::cout<
if(i==in) { if(g_buffer[i]<10) std::cout<<" "; else std::cout<<" "; std::cout<<" <-- 生产者";//输出生产者的指针位置 } if(i==out) { if(g_buffer[i]<10) std::cout<<" "; else std::cout<<" "; std::cout<<" <-- 消费者";//输出消费者的指针位置 } std::cout< } } 4.2.3消费一个产品 void Consume()//消费一个产品 { std::cout< std::cerr<<"消费一个产品: "< std::cout< } 4.2.4从缓冲区中取出一个产品 void Take() { std::cout< std::cerr<<"从缓冲区取出一个产品"; ConsumeID=g_buffer[out]; out=(out+1)%SIZE_OF_BUFFER; std::cerr< std::cout< std::cout<<"缓冲区 产品 生产者/消费者"< //取出一个产品后,输出缓冲区当前的状态 for(int i=0;i { //输出缓冲区下标 if(i<10) std::cout<
else std::cout<
if(i==in) { if(g_buffer[i]<10) std::cout<<" "; else std::cout<<" "; std::cout<<" <-- 生产者";//输出生产者的指针位置 } if(i==out) { if(g_buffer[i]<10) std::cout<<" "; else std::cout<<" "; std::cout<<" <-- 消费者";//输出消费者的指针位置 } std::cout< } }