1、生产者消费者 BoundedBuffer Problem课程设计任务书学生姓名: 专业班级: 软件0703 指导教师: 刘军 工作单位: 计算机科学与技术学院 题目: 实现生产者消费者(Bounded-Buffer Problem) 问题 初始条件:1操作系统:Linux2程序设计语言:C语言3有界缓冲区内设有20个存储单元,其初值为0。放入取出的数据项按增序设定为120这20个整型数。要求完成的主要任务: (包括课程设计工作量及其技术要求,以及说明书撰写等具体要求) 1技术要求:1)为每个生产者消费者产生一个线程,设计正确的同步算法2)每个生产者和消费者对有界缓冲区进行操作后,即时显示有界缓
2、冲区的当前全部内容、当前指针位置和生产者消费者线程的自定义标识符。3)生产者和消费者各有两个以上。4)多个生产者或多个消费者之间须共享对缓冲区进行操作的函数代码。2 设计说明书内容要求:1) 设计题目与要求2) 总的设计思想及系统平台、语言、工具等。3)数据结构与模块说明(功能与流程图)4)运行结果与运行情况(提示: (1)有界缓冲区可用数组实现。(2)编译命令可用:cc -lpthread -o 目标文件名源文件名(3)多线程编程方法参见附件。)3. 调试报告:1) 调试记录2)自我评析和总结上机时间安排:周 一 五 下午 14 :00 18 :00 (6月 15 日开始)指导教师签名: 2
3、010 年 6 月 15 日系主任(或责任教师)签名: 2010 年 6 月 15日实现生产者消费者(Bounded Buffer Problem)问题摘要生产者与消费者问题是操作系统中经典进程同步问题的典型代表。本设计介绍了基于单缓冲区和多缓冲区的生产者与消费者问题在C语言中的多种实现机制。这种用C实现生产者与消费者问题的思想不仅可以更好的理解这方面的内容,而且还具有很强的实践意义。1 设计题目与要求11设计题目:实现生产者消费者(Bounded Buffer Problem)问题12设计要求:通过研究Linux的线程机制和信号量实现生产者消费者(Bounded Buffer)问题的并发控制
4、。2 总的设计思想及系统平台、语言、工具2.1 设计思想:2.1.1具体的要求 (1)每个生产者和消费者对有界缓冲区进行操作后,即时显示有界缓冲区的全部内容.当前指针位置和生产者/消费者线程的标识符 (2)生产者和消费者各有两个以上 (3)多个生产者或多个消费者之间须共享对缓冲区进行操作的函数代码。2.1.2 POSIX无名信号量PV操作是原子操作.也就是操作是不可以中断的,在一定的时间内,只能够有一个进程的代码在CPU上面执行.在系统当中,有时候为了顺利的使用和保护共享资源,提出了信号的概念. POSIX标准提出了有名信号量和无名信号量的概念,由于Linux只实现了无名信号量,我们在这里就只
5、是介绍无名信号量了。信号量的使用主要是用来保护共享资源,使的资源在一个时刻只有一个进程所拥有.为此可以使用一个信号灯.当信号灯的值为某个值的时候,就表明此时资源不可以使用.否则就表示可以使用. 为了提供效率,Linux系统提供了下面几个函数 POSIX的无名信号量的函数有以下几个: int sem_init(sem_t *sem,int pshared,unsigned int value);int sem_destroy(sem_t *sem);int sem_wait(sem_t *sem);int sem_trywait(sem_t *sem);int sem_post(sem_t *s
6、em);int sem_getvalue(sem_t *sem);sem_init创建一个信号灯,并初始化其值为value.pshared决定了信号量能否在几个进程间共享.由于目前Linux还没有实现进程间共享信号灯,所以这个值只能够取0. sem_destroy是用来删除信号灯的.sem_wait调用将阻塞进程,直到信号灯的值大于0.这个函数返回的时候自动的将信号灯的值的件一.sem_post和sem_wait相反,是将信号灯的内容加一同时发出信号唤醒等待的进程.sem_trywait和sem_wait相同,不过不阻塞的,当信号灯的值为0的时候返回EAGAIN,表示以后重试.sem_getv
7、alue得到信号灯的值. 这几个函数的使用相当简单的.比如我们有一个程序要向一个系统请求一个资源时.首先创建一个信号灯,并使其初始值为1,表示有一个资源可用.然后一个进程调用sem_wait由于这个时候信号灯的值为1,所以这个函数返回,打印机开始打印了,同时信号灯的值为0 了. 如果第二个进程要使用,调用sem_wait时候,由于信号灯的值为0,资源不可用,于是被阻塞了.当第一个进程对资源的使用完毕以后,调用sem_post信号灯的值为1了,这个时候系统通知第二个进程,于是第二个进程的sem_wait返回.第二个进程开始工作了.2.1.3 System V信号量为了解决上面的问题,也可以使用S
8、ystem V信号量.并且Linux实现了System V信号量.这样就可以用实例来解释了. System V信号量的函数主要有下面几个. key_t ftok(char *pathname,char proj);int semget(key_t key,int nsems,int semflg);int semctl(int semid,int semnum,int cmd,union semun arg);int semop(int semid,struct sembuf *spos,int nspos);struct sembuf short sem_num; /* 使用那一个信号 */
9、short sem_op; /* 进行什么操作 */short sem_flg; /* 操作的标志 */;ftok函数是根据pathname和proj来创建一个关键字.semget创建一个信号量.成功时返回信号的ID,key是一个关键字,可以是用ftok创建的也可以是IPC_PRIVATE表明由系统选用一个关键字. nsems表明我们创建的信号个数.semflg是创建的权限标志,和创建一个文件的标志相同. semctl对信号量进行一系列的控制.semid是要操作的信号标志,semnum是信号的个数,cmd是操作的命令.经常用的两个值是:SETVAL(设置信号量的值)和IPC_RMID(删除信号
10、灯).arg是一个给cmd的参数. semop是对信号进行操作的函数.semid是信号标志,spos是一个操作数组表明要进行什么操作,nspos表明数组的个数. 如果sem_op大于0,那么操作将sem_op加入到信号量的值中,并唤醒等待信号增加的进程. 如果为0,当信号量的值是0的时候,函数返回,否则阻塞直到信号量的值为0. 如果小于0,函数判断信号量的值加上这个负值.如果结果为0唤醒等待信号量为0的进程,如果小与0函数阻塞.如果大于0,那么从信号量里面减去这个值并返回.2.1.4 pthread_xxx() API主要包含数据结构pthread_t 它记录一个线程的号,主要包括下面几个函数
11、,完成不同的功能: int pthread_create(pthread_t * thread, pthread_attr_t * attr, void *(*start_routine)(void *), void * arg);创建一个线程。 pthread_join(pthread_t * thread,void *return);等待一个线程结束。 pthread_exit(void * returnval);结束一个线程。2.2. 系统平台:一台Linux主机且有超级用户权限2.3. 编程工具:VI编辑器,Gedit编辑器3模块说明3.1生产者进程:if(fork() = 0 ) i
12、nt i = 0; while( i 100) semop(emptyid , &P ,1 ); semop(mutxid , &P , 1); array*(set)%MAXSEM = i + 1; printf(Producer %dn, array(*set)%MAXSEM); (*set)+; semop(mutxid , &V , 1); semop(fullid , &V , 1); i+; /end of while in line 62 sleep(10); printf(Producer is over); exit(0); /3.2 消费者进程:/消费者A进程 if(for
13、k()=0) while(1) semop(fullid , &P , 1); semop(mutxid , &P , 1); if(*get = 100) break; *sum += array(*get)%MAXSEM; printf(The ComsumerA Get Number %dn, array(*get)%MAXSEM ); (*get)+; if( *get =100) printf(The sum is %d n , *sum); semop(mutxid , &V , 1); semop(emptyid , &V ,1 ); sleep(1); /end of whil
14、e(1) in line 82 printf(ConsumerA is over); exit(0); /end of if in line 81 else /消费者B进程 if(fork()=0) while(1) semop(fullid , &P , 1); semop(mutxid , &P , 1); if(*get = 100) break; *sum += array(*get)%MAXSEM; printf(The ComsumerB Get Number %dn, array(*get)%MAXSEM ); (*get)+; if( *get =100) printf(The
15、 sum is %d n , *sum); semop(mutxid , &V , 1); semop(emptyid , &V ,1 ); sleep(1); /end of while(1) in line105 printf(ConsumerB is over); exit(0); /end of if in line 103 /end of else in line 101 4. 源程序: #include #include #include #include #include #include #include #include #define MAXSEM 5/声明三个信号灯IDi
16、nt fullid;int emptyid;int mutxid;int main() struct sembuf P,V; union semun arg; / /声明共享内存 int *array; int *sum; int *set; int *get; /映射共享内存 array = (int *)mmap(NULL , sizeof( int )*5,PROT_READ|PROT_WRITE,MAP_SHARED|MAP_ANONYMOUS,-1,0); sum = (int *)mmap(NULL , sizeof( int ),PROT_READ|PROT_WRITE,MAP_
17、SHARED|MAP_ANONYMOUS,-1,0); get = (int *)mmap(NULL , sizeof( int ),PROT_READ|PROT_WRITE,MAP_SHARED|MAP_ANONYMOUS,-1,0); set = (int *)mmap(NULL , sizeof( int ),PROT_READ|PROT_WRITE,MAP_SHARED|MAP_ANONYMOUS,-1,0); *sum = 0; *get = 0; *set = 0; /生成信号灯 fullid= semget(IPC_PRIVATE,1,IPC_CREAT|00666); empt
18、yid=semget(IPC_PRIVATE,1,IPC_CREAT|00666); mutxid=semget(IPC_PRIVATE,1,IPC_CREAT|00666); /为信号灯赋值 arg.val = 0; if(semctl(fullid , 0 , SETVAL , arg) = -1) perror(semctl setval error); arg.val = MAXSEM; if(semctl(emptyid , 0 ,SETVAL , arg) = -1) perror(semctl setval error); arg.val = 1; if(semctl(mutxi
19、d , 0 ,SETVAL , arg) = -1) perror(setctl setval error); /初始化P,V操作 V.sem_num=0; V.sem_op =1; V.sem_flg=SEM_UNDO; P.sem_num=0; P.sem_op =-1; P.sem_flg=SEM_UNDO; /生产者进程 if(fork() = 0 ) int i = 0; while( i 100) semop(emptyid , &P ,1 ); semop(mutxid , &P , 1); array*(set)%MAXSEM = i + 1; printf(Producer
20、%dn, array(*set)%MAXSEM); (*set)+; semop(mutxid , &V , 1); semop(fullid , &V , 1); i+; /end of while in line 62 sleep(10); printf(Producer is over); exit(0); /end of if in line 59 else /消费者A进程 if(fork()=0) while(1) semop(fullid , &P , 1); semop(mutxid , &P , 1); if(*get = 100) break; *sum += array(*
21、get)%MAXSEM; printf(The ComsumerA Get Number %dn, array(*get)%MAXSEM ); (*get)+; if( *get =100) printf(The sum is %d n , *sum); semop(mutxid , &V , 1); semop(emptyid , &V ,1 ); sleep(1); /end of while(1) in line 82 printf(ConsumerA is over); exit(0); /end of if in line 81 else /消费者B进程 if(fork()=0) w
22、hile(1) semop(fullid , &P , 1); semop(mutxid , &P , 1); if(*get = 100) break; *sum += array(*get)%MAXSEM; printf(The ComsumerB Get Number %dn, array(*get)%MAXSEM ); (*get)+; if( *get =100) printf(The sum is %d n , *sum); semop(mutxid , &V , 1); semop(emptyid , &V ,1 ); sleep(1); /end of while(1) in
23、line105 printf(ConsumerB is over); exit(0); /end of if in line 103 /end of else in line 101 /end of else in line 78 sleep(20); return 0;/end of main5运行结果与运行情况运行截图如下:6调试记录:有三个worning:7自我评析和总结:这次操作系统课程设计,我在设计过程中虽然遇到了困难,但是通过上网查阅资料很好的解决了问题,让我真正理解了Linux内核定时器的本质。 其实这个课程设计是我和同学一起完成的,虽然不是很完美,但是起码能让我们很好的理解了什
24、么是生产者消费者问题。让我对互斥问题有了更深的见解。 8.参考文献1Operating System Concepts(Sixth Edition)(操作系统概念)影印版 Abraham Silberschatz编 高等教育出版社 2003年2计算机操作系统教程(第三版) 张尧学编 清华大学出版社2001年3 操作系统原理(第三版) 庞丽萍 华中科技大学出版社2000年本科生课程设计成绩评定表班级:软件0703姓名: 学号:0120710680319序号评分项目满分实得分1学习态度认真、遵守纪律102设计分析合理性103设计方案正确性、可行性、创造性204设计结果正确性405设计报告的规范性106设计验收10总得分/等级评语:注:最终成绩以五级分制记。优(90-100分)、良(80-89分)、中(70-79分)、及格(60-69分)、60分以下为不及格指导教师签名:2010 年6月15日
copyright@ 2008-2022 冰豆网网站版权所有
经营许可证编号:鄂ICP备2022015515号-1