操作系统课程设计(生产者-消费者问题)_第1页
操作系统课程设计(生产者-消费者问题)_第2页
操作系统课程设计(生产者-消费者问题)_第3页
操作系统课程设计(生产者-消费者问题)_第4页
操作系统课程设计(生产者-消费者问题)_第5页
已阅读5页,还剩12页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

1、 课程设计报告课程名称: 操作系统 班 级: 1305022 学 号: 11 姓 名: 牟 黎 明 指导教师: 龚茗茗老师 计算机工程学院时间:2016.06.06-2016.06.12目 录一、实验概述11实验目的12实验目标13、具体要求如下:14、实验工具2二、实验过程21、实验题目分析22、算法流程23、算法实现34、关键问题35、关键代码分析31.定义的变量:32.关键函数:4CreateThread4信号量对象(semaphore)4等待操作5生产者消费者函数66、程序代码及注释:8三、实验结果与总结91、实验结果92、实验总结9参考文献11附录:111305022 班 11 牟黎

2、明 第2页 目录 共1页一、实验概述1实验目的1、熟悉临界资源、信号量及PV操作的定义与物理意义。2、了解进程通信的方法。3、掌握进程互斥与进程同步的相关知识4、掌握用信号量机制解决进程间的同步和互斥问题。5、实现生产者消费者问题,深刻理解进程同步问题。2实验目标在Linux操作系统下用C实现经典进程同步问题:生产者消费者问题。3、具体要求如下:1、缓冲区大小为5,初始状态为空。2、2个生产者,随机等待一段时间,往缓冲区中添加数据,若缓冲区已满,等待消费者取走数据之后再添加,重复5次3、2个消费者,随机等待一段时间,从缓冲区中读取数据,若缓冲区为空,等待生产者添加数据之后再读取,重复5次。 生

3、产者 Buffer(大小为5) 消费者 4、实验工具开发环境:Visual C+ 6.0二、实验过程1、实验题目分析 本实验要求利用PV操作实现解决生产者消费者问题中的同步问题。此问题描述的是2个生产者进程在生产产品并将这些产品提供给消费者进程去消费,在两者之间设置了一个具有5个缓冲区的缓冲池,生产者进程将它所生产的产品放入一个缓冲区,消费者进程可从缓冲区中取走产品去消费,但它们之间必须保持同步,即不允许消费者进程到一个空缓冲区去取产品,也不允许生产者进程向一个已装满且尚未取出的缓冲区中投放产品,并且生产者消费者互斥使用缓冲区,定义信号量来实现互斥使。2、算法流程 3、算法实现主要用到生产者函

4、数DWORD WINAPI Producer(LPVOID para)来实现缓冲区产品数量的增加,用DWORD WINAPI Consumer(LPVOID para)来实现缓冲区产品的减少。并用到了CreateThread函数来创建生产者消费者线程,利用线程的句柄以及创建线程是立刻运行的特点来进行生产消费操作。至于PV算法的实现是利用mutex、empty和full,3个信号量来进行控制, empty的值可以看做资源量,即当前缓冲区的大小,初始化为缓冲区的大小,只有empty的数值大于0才可以进行生产, full的数值与empty的值有对应的关系,利用full来控制消费的进行。用mutex来

5、实现信号的同步于互斥,当p(mutex)能申请时,就锁住缓冲区,供自己使用,使用完后,用v(mutex)来释放。4、关键问题 利用生产者进程进行生产,同时消费者进程也能进行消费,但是必须满足同步的条件才可以允许,否则将提示缓冲区满无法进行生产或者缓冲区空无法进行消费的错误,其次,必须对公用的临界资源进行互斥使用,生产者生产时消费者不能使用缓冲区,故程序应该具有判断的功能。若结束当前的生产者消费者进程,将会提示此次进程中生产消费者分别生产了和消费的产品数目,并统计缓冲区中剩余的产品数目,最后才结束。5、关键代码分析1.定义的变量:#define BUFFER_NUM 5 /* 缓冲区个数 */

6、struct Buffer /临界区 int productBUFFER_NUM; / 缓冲区 int start, end; / 两个指针 相当于 in out 指针g_buf;typedef HANDLE Semaphore; / 信号量的Windows原型 句柄,唯一标识Semaphore empty, full, mutex; /定义3个信号量,来实现互斥与同步定义PV操作,来实现资源的申请与释放操作(对缓冲区的数目进行操作)#define P(S) WaitForSingleObject(S, INFINITE) /定义c语言stdio.h库中的P操作#define V(S) Rel

7、easeSemaphore(S, 1, NULL) / 定义c语言 stdio.h库中的V操作2.关键函数:CreateThread函数创建一个在调用进程的地址空间中执行的线程。此函数为API函数,用于创建生产者消费者进程。 程序中相关代码: hThreadi = CreateThread(NULL, 0, Consumer, &i, 0, &tid); hThreadi = CreateThread(NULL, 0, Producer, &i, 0, &tid);信号量对象(semaphore)信号量对象实现了Dijkstra定义中的通用信号量语义。信号量对象

8、就是资源信号量,初始值的取值在0到指定最大值之间,用于限制并发访问的线程数,也可用于进程、线程间的同步。它的相关API包括:CreateSemaphore、OpenSemaphore和ReleaseSemaphore。本使用中主要用到了CreateSemaphore和ReleaseSemaphore。(1)CreateSemapore函数是创建一个有名或者无名信号量对象,在输人参数中指定最大值和初值,返回对象句柄。格式:HANDLE CreateSemaphore(LPSECURITY_ATTRIBUTES lpAttributes, LONG lInitialCount, LONG lMax

9、imumCount, LPCTSTR lpName );四个参数说明:1pAttributes:安全属性。如果是NULL就表示要使用默认属性。1InitialCount:Semaphore的初值。必须0,并且MaximumCount。lMaximumCount:Semaphore的最大值。这也就是在同一时间内能够锁住Semaphore之线程的最多个数。1pName:Semaphore的名称(一个字符串)。任何线程(或进程)都可以根据这一名称引用到这个Semaphore。这个值可以是NULL,意思是产生一个没有名字的Semaphore。 返回值:如果成功就传回一个handle,否则传回NULL程

10、序中相关代码:mutex = CreateSemaphore(NULL, 1, 1, TEXT("mutexOfConsumerAndProducer");empty = CreateSemaphore(NULL, BUFFER_NUM, BUFFER_NUM, TEXT("BufferSemaphone");full = CreateSemaphore(NULL, 0, BUFFER_NUM, TEXT("ProductSemaphone");等待操作Windows 2000为对象提供了两个统一的等待操作函数WaitForSingl

11、eObject和WaitForMultipleObjiects,等待函数被同步对象用于实现各种Dijkstra定义的P操作。等待的对象包括:Change notification(改变通告);Console input(控制台输入);Event(事件);Job(作业);Mutex(互斥对象);Process(进程);Semaphore(信号量);Thread(线程);Waitable timer(可等待定时器)。函数决定等待条件是否被满足。如果等待条件并没有被满足,调用线程进入一个高效的等待状态,当等待满足条件时占用非常少的处理器时间。在运行前,一个等待函数修改同步对象类型的状态。修改仅发生在

12、引起函数返回的对象身上。例如,信号的计数减1。一个线程通过调用等待函数拥有对象。创建该对象的线程也拥有对象,而不需要调用等待函数。(1)WaitForSingleObject函数可在指定的时间内等待指定对象为可用状态当下列情况之一发生时该函数返回:(1)指定对象处于信号态;(2)超时。格式:DWORD WaitForSingleObject(HANDLE hHandle, DWORD dwMilliseconds );参数说明: hHandle:等待对象句柄。 dwMilliseconds:指定以毫秒为单位的超时间隔。如果超时,即使对象的状态是非信号态的并且没有完成,函数也返回。如果它是0,函

13、数测试对象的状态并立刻返回;如果它是INFINITE(定义为0xFFFFFFFF或-1),函数从不超时。返回值:如果函数调用成功,返回值表明引起函数返回的事件。可能值如下:WAIT_ABANDONED:指定对象是互斥对象,在线程被终止前,线程没有释放互斥对象。互斥对象的所属关系被授予调用线程,并且该互斥对象被置为非信号态。WAITOBJECT_0:指定对象的状态被置为信号态。WAIT_TIMEOUT:超时,并且对象的状态为非信号态。如果函数调用失败,返回值是WAIT_FAILED。程序中相关代码:if ( hThreadi ) WaitForSingleObject(hThreadi, 10)

14、;(2)WaitForMultipleObjects函数可在指定的时间内等待多个对象为可用状态。格式:DWORD WaitForMultipleObjects(DWORD nCount,CONST HANDLE *lpHandles,BOOL bWaitAll,DWORD dwMilliseconds);参数说明:nCount规定了可引起函数阻塞的一组对象的句柄数目。lpHandles指向存放一组句柄的数组。bWaitAll规定了是否函数应该等待一组对象都发送出有信号通知(bWaitAll=TRUE),或者只是等待一个对象(bWaitAll=FLASE)。dwMilliseconds,它同在W

15、aitForSingleObiect一样。程序中相关代码: WaitForMultipleObjects(totalThreads, hThread, TRUE, INFINITE);生产者消费者函数1、生产者线程DWORD WINAPI Producer(LPVOID para)int i = *(int *)para - CONSUMER_NUM; /得到当前生产者的编号int ptr;/获取缓冲区的位置int data; / 产品int j=0;while (j+<4)time_t tval; /定义时间函数struct tm *now;tval=time(NULL);now=lo

16、caltime(&tval);printf("生产者%01d:准备生产n", i);data = rand()%8; /随机产生一个0-8的随机数P(empty);P(mutex); / 有地方,先锁住缓冲区ptr = g_buf.end; / 记录消费的物品g_buf.end = (g_buf.end+1)%BUFFER_NUM; / 再移动缓冲区指针printf(" 时间:%d月: %02d日: %d:%02d:%02dn",now->tm_mon+1,now->tm_mday,now->tm_hour,now->tm

17、_min,now->tm_sec); /打印出时间printf(" 生产者%01d: 生产 buf%d = %s ", i, ptr, thingdata); / 放好了完毕,释放一个产品printf(" 生产者%01d: 生产完毕 n",i);/ 让其他消费者或生产者使用V(mutex);V(full);Sleep(rand()%10*1000); /等待一段时间0-9秒return 0;2、 消费者线程 就是一个返回 DWORD(32位数据)的 API 函数DWORD WINAPI Consumer(LPVOID para)/LPVOID 是一

18、个没有类型的指针,可以任意存储long型指针/ i表示第i个消费者int i = *(int *)para; /利用para传入当前消费者的编号2int ptr; / 待消费的内容的指针int j=0;while (j+<4)time_t tval; /定义时间函数struct tm *now;tval=time(NULL);now=localtime(&tval);printf("消费者%01d:准备消费n", i); / 等待产品P(full); / 有产品,先锁住缓冲区P(mutex);/ 申请信号量,能申请,锁住。ptr = g_buf.start;/

19、 再移动缓冲区指针g_buf.start = (g_buf.start+1)%BUFFER_NUM;/ 让其他消费者或生产者使用printf(" 时间:%d月: %02d日: %d:%02d:%02dn",now->tm_mon+1,now->tm_mday,now->tm_hour,now->tm_min,now->tm_sec);/打印出当前时间printf(" 消费者%01d: 消费 buf%d",i,g_buf.start);/ 消费完毕,并释放一个缓冲printf(" 消费者%01d: buf%d 消费完

20、毕n",i,g_buf.start);V(mutex);V(empty);Sleep(rand()%10*1000); /等待一段时间0-9秒return 0;3、其它API函数(1)Sleep函数对于指定的时间间隔挂起当前的执行线程。格式:VOID Sleep(DWORD dwMilliseconds );dwMilliseconds:定义挂起执行线程的时间,以毫秒(ms)为单位。取值为0时,该线程将余下的时间片交给处于就绪状态的同一优先级的其他线程。若没有处于就绪状态的同一优先级的其他线程,则函数立即返回,该线程继续执行。若取值为INFINITE则造成无限延迟。返回值:该函数没有

21、返回值。(2) localtime(&tval)函数取得当前的本地时间和日期。time_t tval; /定义时间函数struct tm *now;tval=time(NULL);now=localtime(&tval);输出: (时:分:秒)printf(" 时间: %d:%02d:%02dn", now->tm_hour,now->tm_min,now->tm_sec);6、程序代码及注释:见附录。三、实验结果与总结1、实验结果2、实验总结在此次实验中模拟PV 操作同步机构,来解决生产者消费者问题。此次实验完成了消费者与生产者这两个进程

22、之间的同步协调问题。 值得注意的是解决进程同步需要做哪些工作,如何利用信号量机制来解决进程同步问题等等,这些问题其实我们在学习理论知识时都是很少思考的,因为感触不深,所以学了一遍就过去了,但是在自己做实验时才会发现哪些地方是我们需要考虑的,哪些地方是需要注意的,实验给了我们实践的机会,给了我们理论结合实际的机 会,从实验中可以学到很多东西,不仅仅是书本上的东西这么简单,更重要的是对待事情严谨的态度,对待任何事情都要一丝不苟,细节决定成败! 但发现代码做出来后,对很多理论知识还是不知道。如老师验收时问,什么是临界区,一开始我把临界区和临界资源等同理解了,后来才明白,临界区是一段代码块,只PV操作

23、间的那段代码。所有觉得自己看书还是没真正的看好书。看得很马虎。 总之,通过本次课程设计,我弄明白了进程间的通信机制,熟悉临界资源、信号量及PV操作的定义与物理意义。了解进程通信的方法。掌握进程互斥与进程同步的相关知识,掌握用信号量机制解决进程间的同步和互斥问题,深刻理解生产者消费者进程同步问题。同时,深刻的理会到,学习的确应该手脑并用,学做合一,应该认真仔细的去看书 在此感谢我们的老师,龚茗茗老师,带病陪着我们做完课程设计,并细心为我们答疑解惑。再次感谢!参考文献操作系统教程(第5版) 费翔林 骆 斌 编制 高等教育出版社 C+面向对象程序设计教程(第3版) 陈维兴 林小茶 编制 清华大学出版

24、社 网络查阅资料(百科、博客) 附录主要代码:#include <windows.h>#include <stdio.h>#include <stdlib.h>#include <time.h>typedef HANDLE Semaphore; / 信号量的Windows原型 句柄,唯一标识#define P(S) WaitForSingleObject(S, INFINITE) / 定义c语言 stdio.h库中的P操作#define V(S) ReleaseSemaphore(S, 1, NULL) / 定义c语言 stdio.h库中的V操作

25、#define rate 1000#define CONSUMER_NUM 2 /* 消费者个数 */#define PRODUCER_NUM 2 /* 生产者个数 */#define BUFFER_NUM 5 /* 缓冲区个数 */char *thing8 = "11", "12", "13", "14", "21", "22", "23", "24" /生产和消费的产品名称struct Bufferint productBUFFER

26、_NUM; / 缓冲区int start, end; / 两个指针 相当于 in out 指针g_buf;Semaphore empty, full, mutex; /分别相当于empty, full, mutex互斥信号量三个信号量/ 消费者线程 就是一个返回 DWORD(32位数据)的 API 函数DWORD WINAPI Consumer(LPVOID para)/LPVOID 是一个没有类型的指针,可以任意存储long型指针/ i表示第i个消费者int i = *(int *)para; /利用para传入当前消费者的编号2int ptr; / 待消费的内容的指针int j=0;whi

27、le (j+<4)time_t tval;struct tm *now;tval=time(NULL);now=localtime(&tval);printf("消费者%01d:准备消费n", i); / 等待产品P(full); / 有产品,先锁住缓冲区P(mutex);/ 申请信号量,能申请,锁住。ptr = g_buf.start;/ 再移动缓冲区指针g_buf.start = (g_buf.start+1)%BUFFER_NUM;/ 让其他消费者或生产者使用printf(" 时间:%d月: %02d日: %d:%02d:%02dn"

28、,now->tm_mon+1,now->tm_mday,now->tm_hour,now->tm_min,now->tm_sec);printf(" 消费者%01d: 消费 buf%d",i,g_buf.start);/ 消费完毕,并释放一个缓冲printf(" 消费者%01d: buf%d 消费完毕n",i,g_buf.start);V(mutex);V(empty);Sleep(rand()%10*1000);return 0;/ 生产者线程DWORD WINAPI Producer(LPVOID para)int i

29、= *(int *)para - CONSUMER_NUM; int ptr;int data; / 产品int j=0;while (j+<4)time_t tval;struct tm *now;tval=time(NULL);now=localtime(&tval);printf("生产者%01d:准备生产n", i);data = rand()%8;P(empty);/ 有地方,先锁住缓冲区P(mutex);/ 记录消费的物品ptr = g_buf.end;/ 再移动缓冲区指针g_buf.end = (g_buf.end+1)%BUFFER_NUM;p

30、rintf(" 时间:%d月: %02d日: %d:%02d:%02dn",now->tm_mon+1,now->tm_mday,now->tm_hour,now->tm_min,now->tm_sec);printf(" 生产者%01d: 生产 buf%d = %s ", i, ptr, thingdata); / 放好了完毕,释放一个产品printf(" 生产者%01d: 生产完毕 n",i);/ 让其他消费者或生产者使用V(mutex);V(full);Sleep(rand()%10*1000);return 0;int main(int argc, char *argv)/

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论