您好,欢迎访问三七文档
当前位置:首页 > 商业/管理/HR > 销售管理 > 北邮操作系统消费者与生产者实验报告
1/9操作系统实验课程报告课题:消费者与生产者实验姓名张涛学院计算机学院班级2011211311学号20112114192013年12月14日2/91.实验目的:1)理解线程同步的思想和方法,学会用线程同步解决临界区问题,本次实验解决生产者消费者问题2了解windows系统或linux系统下中信号量的使用方法。2.实验预备内容(1)阅读Linux的sched.h源码文件,加深对进程管理概念的理解。这个文件长达2616行,这里截取第1221~1548行抄录在实验报告最后,即结构体task_struct,地位相当于PCB。下面对几个比较重要的参数,结合本人的了解以及网上查阅的资料做一点解释。中括号内的数字为代码行号,下同。volatilelongstate:【1222】进程状态字,表示进程当前的状态(运行、就绪、等待、僵死、暂停、交换),分别对应已定义好的常量;TASK_RUNING:正在运行或可运行状态;TASK_INTERRUPTIBLE:可打断睡眠状态;TASK_UNINTERRUPTIBLE:不可打断睡眠状态;TASK_ZOMBLE:僵死状态;TASK_STOPPED:暂停状态;交换状态。void*stack:【1223】进程所使用的栈空间;unsignedintflags:【1225】进程标志(创建、关闭、跟踪、被跟踪、内核dump等),同样对应已定义好的常量;unsignedintrt_priority:【1237】表示本进程的实时优先级;conststructsched_class*sched_class、structsched_entityse:【1239,1240】分别是调度类和调度实体,这两个结构包含了用于任务调度的完整的信息(进程信息、调度策略等);unsignedintpolicy:【1260】进程的调度策略标志,有三种调度标志:SCHED_OTHER:普通进程的调度策略,基于优先权的轮转法;SCHED_FIFO:实时进程的调度策略,基于先进先出的算法;SCHED_RR:实时进程的调度策略,基于优先权的轮询法。structlist_headtasks:【1274】任务队列,为一双向循环链表;intpdeath_signal:【1282】父进程终止时产生的信号;pid_tpid:【1294】进程标识符,操作系统每创建一个新的进程就要为这个新进程分配一个进程控制块(PCB),系统内核通过pid区分这些进程的;structtask_struct*real_parent:【1307】本进程的父进程的PCB;structlist_headchildren:【1312】本进程的子进程列表;structlist_headptraced:【1321】本进程正在使用ptrace监视的进程列表;structthread_structthread:【1375】本进程下属的线程集;structsignal_struct*signal、structsighand_struct*sighand:【1383,1384】分别是进程运行时产生的信号以及信号处理模块。(2)阅读Linux的pthread.h源码文件,分析线程的创建过程。3/9pthread接口说明#includepthread.h1、创建intpthread_create(pthread_t*tid,constpthread_attr_t*attr,void*(*func)(void*),void*arg);attr:线程属性包括:优先级、初始栈大小,是否应该成为一个守护线程。缺省设置,NULL后面是线程要执行的函数和参数成功返回02、等待一个给定线程终止intpthread_join(pthread_ttid,void**status);等待线程结束critiction可以在进程中使用,mutex只可在进程中使用statues返回等待线程的返回值multipledefinitionof`__dso_handle'/usr/lib/gcc/i486-linux-gnu/4.4.3/crtbegin.o:(.data+0x0):firstdefinedherethreadTest:Infunction`_init':(.init+0x0):multipledefinitionof`_init'/usr/lib/gcc/i486-linux-gnu/4.4.3/../../../../lib/crti.o:(.init+0x0):firstdefinedhere/tmp/cchm2SmY.o:(.data+0x0):multipledefinitionof`flag'threadTest:(.data+0x8):firstdefinedhere/tmp/cchm2SmY.o:Infunction`threadMe3、得到自身的pidpthread_tpthread_self(void);4、pthread_detach函数intpthread_detach(pthread_tpid);把指定的线程转变为脱离状态一个线程或者是可汇合的(joinable,缺省值),或者是脱离的(detached)。当一个可汇合的线程终止时,它的线程ID和退出状态将留到另一个线程对它调用pthread_join。脱离线程却象守护进程:当它们终止的时,所有相关资源都被释放,我们不能等待它们终止。如果一个线程需要知道另一个线程什么时候终止,那就最好好吃第二个线程的可汇合状态。本函数通常由想让自己脱离的线程调用,如下语句pthread_detach(pthread_self());5、终止一个线程voidpthread_exit(void*statue);指针sttus不能指向局部于调用对象,因为线程终止时这样的对象也消失(3)阅读Linux的semaphore.h源码文件,分析线程的创建过程。typedefstructsem_t_*sem_t;PTW32_DLLPORTint__cdeclsem_init(sem_t*sem,intpshared,unsignedintvalue);PTW32_DLLPORTint__cdeclsem_destroy(sem_t*sem);PTW32_DLLPORTint__cdeclsem_trywait(sem_t*sem);PTW32_DLLPORTint__cdeclsem_wait(sem_t*sem);PTW32_DLLPORTint__cdeclsem_post(sem_t*sem);PTW32_DLLPORTint__cdeclsem_post_multiple(sem_t*sem,4/9intcount);PTW32_DLLPORTint__cdeclsem_close(sem_t*sem);PTW32_DLLPORTint__cdeclsem_unlink(constchar*name);intsem_init(sem_t*sem,intpshared,unsignedintvalue)。用于信号量的初始化,第一个参数为信号量的名称,第二个参数为信号量的共享属性,一般设为0(不共享),第三个参数为信号量的初始值。intsem_wait(sem_t*sem)。相当于上面的wait()操作,作用是当信号量的值大于0时,给信号量的值减1,否则会阻塞直至信号量的值大于0。它是一个原子操作。intsem_post(sem_t*sem)。相当于上面的signal()操作,作用是给信号量的值加1。它也是一个原子操作。******************************************************************************/3.实验环境此实验采用的是Win8下MicrosoftVisualStdio2012工程。由于系统不包含semaphore.h,sched.h及pthread.h头文件,所以这些头文件都是从网上FTP资源下载后,加入工程的。程序中加入#pragmacomment(lib,pthreadVC2.lib)来调用pthread链接库。文件根目录下已下载pthreadVC2.dll******************************************************************************/4.实验步骤A.设计思路这个问题是进程同步的经典问题之一,基本思路是设置三个信号量:mutex信号量,用于控制生产者和消费者对于缓冲区的互斥访问;empty信号量,记录当前为空的缓冲区的数目,初始化为所有缓冲区的数目BUF_SIZE;full信号量,记录当前已满的缓冲区的数目,初始化为0。******************************************************************************/一个buffer,一个生产者,一个消费者(1)规则只有buffer为空才能put;只有buffer中有数据才能get;不允许多个put操作同时进行;不允许多个get操作同时进行。这时buffer变成了临界资源,消费者之间需要互斥地使用,生产者之间也需要互斥地使用,消费者和生产者之间也需要互斥地使用,这时设置两个信号量s1,s2实现同步,例外设置S信号,代表buffer这种临界资源,用于互斥,称之为互斥信号量。(2)实现流程生产者p(s1)判断buffer是否空5/9p(s)是否可进行put,是否有其他进程占用bufferputv(s)释放buffer,让其他进程可以使用v(s2)给消费者进程释放一个buffer中有数据的信号消费者p(s2)判断是否有数据p(s)是否可进行get,是否有其他进程占用getv(s)释放buffer,让其他进程可以使用v(s1)给生产者释放一个buffer为空的信号通过3个信号量,实现了消费者和生产者之间同步关系,也保证了在某个时刻只有一个进程使用临界资源buffer。生产者进程的代码结构描述如下:while(true){nextp=produce();wait(empty);wait(mutex);put(nextp);signal(mutex);signal(full);}消费者进程的代码结构描述如下:while(true){wait(full);wait(mutex);nextc=get();signal(mutex);signal(empty);consume(nextc);}这里两个wait语句的次序并不能调换,这是因为如果将两个wait操作即wait(full)和wait(mutex)互换位置,或者将release(mutex)与release(full)互换位置,当缓冲区存满产品时,生产者又生产了一件产品,它欲向缓冲区存放时将在empty上等待,但它已经占有了使用缓冲区的权利。这时消费者要取产品时将停留在mutex上得不到使用缓冲区的权利,导致生产者等待消费者取走产品,而消费者却在等待生产者释放使用缓冲区的权利,这种相互等待永远结束不了。因此进程将会发生死锁。******************************************************************************/B.实验代码分析生产者:/**Producer*Produceitemsandtrytoputitintothebuffer*Ifthebufferisfull,waiting*Whenproduced,weoutputlikethat:Producer2produced222*Whensuccessfullyput,weoutput:Producer2haveputproduct222intothebufferafter100milliseconds*Themillisecondsisthetimespanfromtheproducerproducedt
本文标题:北邮操作系统消费者与生产者实验报告
链接地址:https://www.777doc.com/doc-4253887 .html