《操作系统》实验报告 生产者-消费者_第1页
《操作系统》实验报告 生产者-消费者_第2页
《操作系统》实验报告 生产者-消费者_第3页
《操作系统》实验报告 生产者-消费者_第4页
《操作系统》实验报告 生产者-消费者_第5页
已阅读5页,还剩12页未读 继续免费阅读

下载本文档

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

文档简介

数学与信息技术学院PAGEPAGE1 南京晓庄学院 《操作系统》实验报告指导老师:专业班级:学号: 姓名: 完成日期:数学与信息技术学院一、实验概述1.实验目的深入了解掌握进程的同步、互斥机制,认识理解其调度过程,并用于解决实际生产者/消费者问题。使用高级编程语言现“生产者——消费者”进程同步问题。2.实验目标(1)对课本知识加以巩固,在实践中提高动手能力;(2)完整的完成此次实验,并有所创新与突破;(3)独立思考,充分利用网络资源与图书资源;(4)取得一个被老师认可的高分评价;二、实验工具1.操作系统:windows2003serverenterprise2.开发环境:VisualStudio2010三、实验过程1、实验具体题目,分析题目:本实验要求利用PV操作实现解决生产者——消费者问题中的同步问题。此问题描述的是一群生产者进程在生产产品并将这些产品提供给消费者进程去消费,在两者之间设置了一个具有n个缓冲区的缓冲池,生产者进程将它所生产的产品放入一个缓冲区,消费者进程可从缓冲区中取走产品去消费,但它们之间必须保持同步,即不允许消费者进程到一个空缓冲区去取产品,也不允许生产者进程向一个已装满且尚未取出的缓冲区中投放产品,并且生产者消费者互斥使用缓冲区。算法流程:算法实现主要用到生产者函数RP-ProceducerThread(void*p)来实现缓冲区产品数量的增加,用RP-ConsumerThread(void*p)来实现缓冲区产品的减少。并用到了CreateThread函数来创建生产者消费者线程,利用线程的句柄以及创建线程是立刻运行的特点来进行生产消费操作。至于PV算法的实现是利用buffer_empty和buffer_full来进行控制,buffer_empty的值可以看做资源量,只有空的数值大于0才可以进行生产,buffer_full的数值与buffer_empty的值有对应的关系,利用buffer_full来控制消费的进行。最后,在缓冲区操作临界资源PC_Buffer来说利用EnterCriticalSection(&PC_Buffer);//等待共享资源LeaveCriticalSection(&PC_Buffer);//释放共享资源来进行缓冲区操作的控制。总之当程序读入测试文件中的数据时,便根据读入的字符时C还是P创造相应的进程,在分配EMPTY或者FULL资源,然后等待共享资源PC_Buffer,得到后便进行操作。最后读入所有的数据,完成所有进程的操作。需要解决的问题:利用生产者进程进行生产,同时消费者进程也能进行消费,但是必须满足同步的条件才可以允许,否则将提示缓冲区满无法进行生产或者缓冲区空无法进行消费的错误,故程序应该具有判断的功能。若结束当前的生产者——消费者进程,将会提示此次进程中生产消费者分别生产了和消费的产品数目,并统计缓冲区中剩余的产品数目,最后才结束。5、关键代码分析:1、做出如下定义CRITICAL_SECTIONPC_Buffer;//临界区HANDLEh_semaphore_empty,h_semaphore_full;//信号量对象structBuffer{charbuf[BUFFER_LEN];}Buf[MAX_THREAD_NUM];intin=0;//生产者生产指针intout=0;//消费者消费指针SYSTEMTIMEtimeSys;CRITICAL_SECTIONPC_Buffer;//临界区HANDLEh_semaphore_empty,h_semaphore_full;//信号量对象structThreadInfo{intserial;//线程序号charentity;//线程类别(P-生产者线程,C-消费者线程)doubledelay;//生产产品/延续时间doublepersist;//线程把产品加入到缓冲区/持续时间};2①CreateThread函数创建一个在调用进程的地址空间中执行的线程。此函数为API函数,用于创建生产者消费者进程。②信号量对象(semaphore)信号量对象实现了Dijkstra定义中的通用信号量语义。信号量对象就是资源信号量,初始值的取值在0到指定最大值之间,用于限制并发访问的线程数,也可用于进程、线程间的同步。它的相关API包括:CreateSemaphore、OpenSemaphore和ReleaseSemaphore。(1)CreateSemapore函数是创建一个有名或者无名信号量对象,在输人参数中指定最大值和初值,返回对象句柄。格式:HANDLECreateSemaphore(LPSECURITY_ATTRIBUTESlpAttributes,LONGlInitialCount,LONGlMaximumCount,LPCTSTRlpName);1pAttributes:安全属性。如果是NULL就表示要使用默认属性。1InitialCount:Semaphore的初值。必须≥0,并且≤MaximumCount。lMaximumCount:Semaphore的最大值。这也就是在同一时间内能够锁住Semaphore之线程的最多个数。1pName:Semaphore的名称(一个字符串)。任何线程(或进程)都可以根据这一名称引用到这个Semaphore。这个值可以是NULL,意思是产生一个没有名字的Semaphore。返回值:如果成功就传回一个handle,否则传回NULL③等待操作Windows2000为对象提供了两个统一的等待操作函数WaitForSingleObject和WaitForMultipleObjiects,等待函数被同步对象用于实现各种Dijkstra定义的P操作。等待的对象包括:Changenotification(改变通告);Consoleinput(控制台输入);Event(事件);Job(作业);Mutex(互斥对象);Process(进程);Semaphore(信号量);Thread(线程);Waitabletimer(可等待定时器)。函数决定等待条件是否被满足。如果等待条件并没有被满足,调用线程进入一个高效的等待状态,当等待满足条件时占用非常少的处理器时间。在运行前,一个等待函数修改同步对象类型的状态。修改仅发生在引起函数返回的对象身上。例如,信号的计数减1。一个线程通过调用等待函数拥有对象。创建该对象的线程也拥有对象,而不需要调用等待函数。(1)WaitForSingleObject函数可在指定的时间内等待指定对象为可用状态当下列情况之一发生时该函数返回:(1)指定对象处于信号态;(2)超时。格式:DWORDWaitForSingleObject(HANDLEhHandle,DWORDdwMilliseconds);hHandle:等待对象句柄。dwMilliseconds:指定以毫秒为单位的超时间隔。如果超时,即使对象的状态是非信号态的并且没有完成,函数也返回。如果它是0,函数测试对象的状态并立刻返回;如果它是INFINITE(定义为0xFFFFFFFF或-1),函数从不超时。返回值:如果函数调用成功,返回值表明引起函数返回的事件。可能值如下:WAIT_ABANDONED:指定对象是互斥对象,在线程被终止前,线程没有释放互斥对象。互斥对象的所属关系被授予调用线程,并且该互斥对象被置为非信号态。WAITOBJECT_0:指定对象的状态被置为信号态。WAIT_TIMEOUT:超时,并且对象的状态为非信号态。如果函数调用失败,返回值是WAIT_FAILED。(2)WaitForMultipleObjects函数可在指定的时间内等待多个对象为可用状态。格式:DWORDWaitForMultipleObjects(DWORDnCount,CONSTHANDLE*lpHandles,BOOLbWaitAll,DWORDdwMilliseconds);nCount规定了可引起函数阻塞的一组对象的句柄数目。lpHandles指向存放一组句柄的数组。bWaitAll规定了是否函数应该等待一组对象都发送出有信号通知(bWaitAll=TRUE),或者只是等待一个对象(bWaitAll=FLASE)。dwMilliseconds,它同在WaitForSingleObiect一样。④临界区对象临界区对象只能用于在同一个进程内使用的临界区,同一个进程内各线程对它的访问是互斥进行的,临界区对象的运行速度比互斥对象快。把变量说明为CRITICAL_SECTION类型,就可作临界区使用。相关的API包括InitializeCriticalSection、EnterCriticalSection、TryEnterCriticalSection、LeaveCriticalSection和DeleteCriticalSection。(1)InitializeCriticalSection函数初始化临界区对象。格式:VOIDInitializeCriticalSection(LPCRITICAL_SECTIONlpCriticalSection);lpCriticalSection:指向临界区对象的指针。(2)EnterCriticalSection函数是等待指定临界区对象的所有权。当调用线程被赋予所有权时,该函数返回。格式:VOIDEnterCriticalSection(LPCRITICAL_SECTIONlpCriticalSection);lpCriticalSection:指向临界区对象的指针。(3)LeaveCriticalSection函数释放指定临界区对象的所有权格式:VOIDLeaveCriticalSection(LPCRITICAL_SECTIONlpCriticalSection);1pCriticalSection:指向临界区对象的指针。(4)DeleteCriticalSection释放与临界区对象相关的所有系统资源。(5)临界区对象的应用例进程通过声明CRITICAL_SECTION类型的变量来完成分配临界区对象使用的存储空间,使用InitializeCriticalSection来初始化该临界区对象。线程在进入临界区之前使用EnterCriticalSection等待占用临界区的使用权,线程在退出临界区之后马上使用LeaveCriticalSection释放临界区的使用权。利用临界区对象实现一个进程的各线程互斥的程序如下:……CRITICAL_SECTIONPC_Buffer;structThreadInfo{……};voidRP_ProceducerThread(void*p){……EnterCriticalSection(&PC_Buffer);//等待共享资源……(临界区)//生产者把产品加入到缓冲区LeaveCriticalSection(&PC_Buffer);//释放共享资源……}intmain(intargc,char*argv[]){HANDLEh_Thread;DWORDthread_ID;ThreadInfothread_info[MAX_THREAD_NUM];InitializeCriticalSection(&PC_Buffer);……h_Thread=CreateThread(NULL,0,(LPTHREAD_START_ROUTINE)(RP_ProceducerThread),&thread_info[i],0,&thread_ID);……}⑤生产者消费者函数voidRP_ProceducerThread(void*p){DWORDm_delay;//生产产品延续时间DWORDm_persist;//把产品加入到缓冲区持续时间intm_serial;//线程序号DWORDwait_for_semaphore_empty;//等待资源信号量所有权longcount;//从参数中获得信息m_serial=((ThreadInfo*)(p))->serial;m_delay=(DWORD)(((ThreadInfo*)(p))->delay*INTE_PER_SEC);m_persist=(DWORD)(((ThreadInfo*)(p))->persist*INTE_PER_SEC);Sleep(m_delay);//生产产品printtime("Producer","requests",m_serial);wait_for_semaphore_empty=WaitForSingleObject(h_semaphore_empty,-1);//等待资源信号量emptyEnterCriticalSection(&PC_Buffer);//等待共享资源printtime("Producer","begins",m_serial);Sleep(m_persist);//生产者把产品加入到缓冲区printtime("Producer","finishs",m_serial);LeaveCriticalSection(&PC_Buffer);//释放共享资源ReleaseSemaphore(h_semaphore_full,1,&count);//释放资源信号量full}voidRP_ConsumerThread(void*p){DWORDm_delay;//消费产品持续时间DWORDm_persist;//从缓冲区取出产品持续时间intm_serial;//消费线程序号DWORDwait_for_semaphore_full;//等待资源信号量longcount;//从参数中获得信息m_serial=((ThreadInfo*)(p))->serial;m_delay=(DWORD)(((ThreadInfo*)(p))->delay*INTE_PER_SEC);m_persist=(DWORD)(((ThreadInfo*)(p))->persist*INTE_PER_SEC);Sleep(m_delay);printtime("Consumer","requests",m_serial);wait_for_semaphore_full=WaitForSingleObject(h_semaphore_full,-1);//等待资源信号量fullEnterCriticalSection(&PC_Buffer);//等待共享资源printtime("Consumer","begins",m_serial);Sleep(m_persist);//消费者从缓冲区取出产品printtime("Consumer","finishs",m_serial);LeaveCriticalSection(&PC_Buffer);//释放共享资源ReleaseSemaphore(h_semaphore_empty,1,&count);//释放资源信号量emptySleep(m_delay);//消费者消费产品}3.其它API函数(1)Sleep函数对于指定的时间间隔挂起当前的执行线程。格式:VOIDSleep(DWORDdwMilliseconds);dwMilliseconds:定义挂起执行线程的时间,以毫秒(ms)为单位。取值为0时,该线程将余下的时间片交给处于就绪状态的同一优先级的其他线程。若没有处于就绪状态的同一优先级的其他线程,则函数立即返回,该线程继续执行。若取值为INFINITE则造成无限延迟。返回值:该函数没有返回值。(2)GetLocalTime函数取得当前的本地时间和日期。格式:BOOLGetLocalTime(lpst);lpst:指向一个SYSTEMTIME结构,该结构存放当前的本地时间和日期。typedefstruct_SYSTEMTIME{WORDwYear;WORDwMonth;WORDwDayOfWeek;WORDwDay;WORDwHour;WORDwMinute;WORDwSecond;WORDwMilliseconds;}SYSTEMTIME;四、实验心得1、实验结果。截图。2、错误与分析。该程序总体上来看比较简单,在调试过程中只要注意一些小问题,则不会出现问题了,除了少许语法错误外,控制好程序的走向,则逻辑错误亦可避免;程序的总体思路很清晰,最主要的就是要实现两个条件判断,即缓冲区满的时候不允许生产者进行生产,若缓冲区空的话,则不进行消费者进行消费;在生产操作和消费操作之间进行相应的判断,正好符合PV信号量,先做P操作,若满足,则执行此进程,若不满足,则阻塞此进程,并做相应的V操作,即唤醒其对应的进程,从而很好的解决了生产者——消费者问题3、心得体会;在此次实验中我们模拟PV操作同步机构,来解决生产者——消费者问题。此次实验完成了消费者与生产者这两个进程之间的同步协调问题。值得注意的是解决进程同步需要做哪些工作,如何利用信号量机制来解决进程同步问题等等,这些问题其实我们在学习理论知识时都是很少思考的,因为感触不深,所以学了一遍就过去了,但是在自己做实验时才会发现哪些地方是我们需要考虑的,哪些地方是需要注意的,实验给了我们实践的机会,给了我们理论结合实际的机会,从实验中可以学到很多东西,不仅仅是书本上的东西这么简单,更重要的是对待事情严谨的态度,对待任何事情都要一丝不苟,细节决定成败!附录:·主要代码//publick.cpp:定义控制台应用程序的入口点。//#include"stdafx.h"#include<stdio.h>#include<stdlib.h>#include<conio.h>#include<windows.h>#defineNULL0structspcb{charname;charstate;charwhy;intdd;};typedefstructspcbpcb;pcbproducter,consumer,*process,*process1;ints1,s2,i,j,in,out,pc,m;chararray[10];charc,x;intpa[6],sa[6];intp(ints)/*p操作原语*/{ s=s-1; if(s<0) { process->state='B';/*B表示阻塞*/ process->why='s'; } else { process->state='W';/*W表示就绪*/ } return(s);}intv(ints)/*v操作原语*/{ s=s+1; if(s<=0) { process1->state='W'; } process->state='W'; return(s);}charRanChar(){ chararr[10]={'a','b','c','d','e','f','g','h','i','j'}; returnarr[abs(rand()%10)];}voidput(){// printf("\npleaseproductanychar!");// scanf("\n%c",&c); Sleep(1000); array[in]=RanChar(); in=(in+1)%10; printf("productacharis%c!\n",array[in-1]); intk=0;for(intm=0;m<10;m++) { if(array[m]!=''){ printf("%c",array[m]); k=k+1; } } printf("缓冲池中有%d个产品\n",k);}voidget(){ Sleep(1000); x=array[out];printf("\n%cgetacharfronbuffer",x); printf("\n");array[out]=''; out=(out+1)%10;intk=0;for(m=0;m<10;m++) { if(array[m]!=''){ printf("%c",array[m]); k=k+1; } } printf("缓冲池中有%d个产品\n",k);}voidgotol(){ pc=0;}voidnop(){;}voiddisp()/*建立进程显示函数,用于显示当前进程*/{ printf("\nname\tstate\twhy\tdd\n"); printf("|%c\t",process->name); printf("|%c\t",process->state); printf("|%c\t",process->why); printf("|%d\t",process->dd); printf("\n");}voidinit()/*初始化程序*/{ s1=10;/*s1表示空缓冲区的数量*/ s2=0;/*s2表示满缓冲区的数量*/ ='p';/*对生产者进程初始化*/ producter.state='W'; producter.why=''; producter.dd=0; ='c';/*对消费者进程初始化*/ consumer.state='W'; consumer.why=''; consumer.dd=0; for(intk=0;k<10;k++) { array[k]=''; }}voidbornpa()/*将生产者程序装入pa[]中*/{ for(i=0;i<=3;i++) { pa[i]=i; }}voidbornsa()/*将消费者程序装入sa[]中*/{ for(i=0;i<=3;i++) { sa[i]=i; }}voidd

温馨提示

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

评论

0/150

提交评论