
信息科学与工程学院
课程设计任务书
题目: 生产者-消费者问题的实现
姓 名:
学 号:
专 业: 计算机科学与技术
课 程: 操作系统
指导教师: 刘彩霞 职称: 讲师
完成时间: 2012年 5月----2012 年 6月
枣庄学院信息科学与工程学院制
课程设计任务书及成绩评定
课程设计的任务和具体要求
1、课程设计的任务:利用所学知识模拟并实现生产者消费者问题;
2、课程设计的具体要求:
(1)为每个生产者/消费者产生一个线程,设计正确的同步算法。
(2)每个生产者和消费者对有界缓冲区进行操作后,即时显示有界缓冲区的当前全部内容、当前指针位置和生产者/消费者线程的自定义标识符。
(3)生产者和消费者各有两个以上。
(4)多个生产者或多个消费者之间须共享对缓冲区进行操作的函数代码。
(5)要求所撰写的课程设计任务书的内容和格式符合要求。
| 指导教师签字: 日期: | |||||
| 指导教师评语 成绩: 指导教师签字: 日期: | |||||
课程设计所需软件、硬件等 Windows xp系统 VM虚拟机并安装redhat linux系统 软件:Vi编辑器 GCC4.41 设计语言:C语言 | |||||
| 课程设计进度计划 | |||||
| 起至日期 | 工作内容 | 备注 | |||
| 2012.5.1—5.15 2012.5.16—6.10 2012.6.11—6.15 2012.6.16—6.20 | 确定课题并收集资料 整体规划并进行初步定位 编写程序代码并进行试验 撰写课程设计任务书 | ||||
| 参考文献、资料索引 | |||||
| 序号 | 文献、资料名称 | 编著者 | 出版单位 | ||
| [1]《操作系统概念(第六版)》,(美)Abraham Silberschatz ,Peter Baer Galvin,Greg Gagne著,郑扣根 译, 高等教育出版社 [2] 《深入理解LINUX内核(第三版)》 (美) 博韦,西斯特 著,陈莉君,张琼声,张宏伟 译,中国电力出版社 | |||||
1.1 设计背景
生产者-消费者问题是一个经典的进程同步问题,该问题最早由Dijkstra提出,用以演示他提出的信号量机制。在同一个进程地址空间内执行的两个线程。生产者线程生产物品,然后将物品放置在一个空缓冲区中供消费者线程消费。消费者线程从缓冲区中获得物品,然后释放缓冲区。当生产者线程生产物品时,如果没有空缓冲区可用,那么生产者线程必须等待消费者线程释放出一个空缓冲区。当消费者线程消费物品时,如果没有满的缓冲区,那么消费者线程将被阻塞,直到新的物品被生产出来。
1.2 问题分类
根据缓冲区的个数、大小以及生产者消费者的个数可以分为以下几类:
1.单缓冲区(适合单或多生产消费者);
2.环行多缓冲区(或无穷缓冲区)单生产消费者;
3.环行多缓冲区多生产消费者;
1.3 解决方案
1.用进程通信(信箱通信)的方法解决;
2.进程消息缓冲通信;
3.进程信箱通信;
第2章 设计思路及原理
设计了两个主要函数:生产者函数、消费者函数;
设计了三个信号量:full信号量 ,判断缓冲区是否有值,初值为0;
empty信号量,判断缓冲区是否有空缓冲区,初值为缓冲区数;
mutex信号量作为互斥信号量,用于互斥的访问缓冲区。
生产者函数通过执行P操作信号量empty减1,判断缓冲区是否有空。有空则互斥的访问缓冲区并放入数据,然后释放缓冲区,执行V操作,信号量full加1。
消费者函数执行P操作,信号量full减1,判断是否有数据,有则互斥的访问缓冲区并取走数据,然后释放缓冲区,执行V操作,empty信号量加1。
第3章 程序详细设计
3.1程序模块设计
该实验主要分为三大模块:
1.主程序,创建并控制程序的流程,
其中控制线程的活动以及信号量的操作,如图3-1-1所示;
2.生产者模块:生产者对缓冲区的操作,如图3-1-2所示;
3.消费者模块:消费者对缓冲区的操作,如图3-1-3所示。
程序相关模块的流程图
图3-1-1 主程序
图3-1-2生产者 图3-1-3消费者
3.2程序代码结构
通过分析,我们已经了解到了可以采用信号量来解决n个进程的临界区问题,这n个进程共享一个信号量mutex(mutual exclusion),并初始化为1。每个进程Pi的组织结构如下图。
由于本系统我们研究的是有限缓冲区(Bounded-Buffer)的生产者消费者问题。而且根据初始条件可知,该缓冲区内有20个缓冲项,每个缓冲项存储一个整形数。信号量mutex提供了对缓冲池访问的互斥要求,并初始化为1。信号量empty和full分别用来表示空缓冲项和满缓冲项的数量。信号量empty初始化为20,而信号量full初始化为0;
生产者进程和消费者进程的代码如图。注意生产者和消费者之间的对称性可以这样来理解代码:生产者为消费者生产满缓冲项,或消费者为生产者生产空缓冲项。
第4章 实验结果
实验结果如截图所示:
图4-1 实验结果截图
第5章 实验总结
进程的同步与互斥是操作系统课程中非常重要的一部分内容。通过本次课程设计,我和我的组员不仅学会了使用信号量机制解决有限缓冲区的生产者消费者问题,而且对Linux系统下多线程编程有了更深入的了解。
虽然实验以前我已经对信号量机制解决进程间同步问题的原理有了很清楚的认识,但是此次课程设计中仍然遇到了很多问题,如Linux系统下各种系统调用以及函数的各种参数,都花费了我很多时间去网上看各种资料——虽然Linux系统中可以很方便的阅读源代码以及使用man命令进行相应指令的查看,但是全英文的资料让人看了不免有些发怵,看来还要多多加强计算机专业英语的学习,以后便可以在Linux系统中查看各种帮助文件。
另一个问题就是在编译的时候遇到的,刚开始用gcc –o main main.c 进行编译的时候总是提示出错,后来查了相关资料才知道pthread 库不是 Linux 系统默认的库,连接时需要使用静态库 libpthread.a,所以在使用pthread_create()等函数时,需要链接该库才能编译通过。以前再用Windows IDE进行编程的时候基本上不会遇到这样的问题,看来的确IDE为我们做了很多工作,隐藏了一些技术细节,有时候隐藏这些细节虽然可以方便我们,却让我们离越来越远。
最近使用Linux进行相关的编程操作,感悟还是挺多的。Windows下的层层封装的确让我们感到很方便,但同时也让我们编程变得越来越不灵活。因为我们不用再去了解底层的东西因此一遇到问题就会束手无策。这段时间一直用Linux进行编程,感觉很方便,跟我以前想象地完全不一样,而且我掌握了不少命令,比我以前用鼠标操作的时候快多了,而且在Bash下可以用Ctrl+Z随时中止正在运行的进程或命令,再用fg %id 重新运行。Linux下的编程也很方便,我还了解了Makefile的编写方法,在多文件编程的时候可以极高地提高效率。 总之,我之后会加强专业英语的学习,以便更好的利用Linux操作系统进行编程之路的学习。
附录:实验代码
#include #include #include #include #include #include #define num_producer 3 #define num_consumer 3 //由于题目要求生产者和消费者各有两个以上,故此处均定为3个 #define BUFFER_SIZE 20 //定义缓冲区的大小,按题目要求为20 int NUM=1; //题目要求放入/取出的数据项按增序设定为1-20,因此定义此全局变量 int buffer[BUFFER_SIZE]; int nextp=0,nextc=0; sem_t empty,full,mutex; //主函数 int main() { int i; signal(SIGALRM,handler); sem_init(&empty,0,BUFFER_SIZE); sem_init(&full,0,0); sem_init(&mutex,0,1); for(i=0;i sem_destroy(&full); sem_destroy(&mutex); return 0; } //消费者代码 void *consumer_thread(void *tid) { int i; pthread_setcancelstate(PTHREAD_CANCEL_ENABLE,NULL); while(1) { sem_wait(&full); srand((int)time(NULL)*(int)tid); sem_wait(&mutex); printf("消费者标识:%d\指针位置:%d\\\n",(int)tid,nextc); buffer[nextc]=0; nextc=(nextc+1)%20; printf("缓冲区:"); for(i=0;i printf("%3d",buffer[i]); } printf("\\n"); sem_post(&mutex); sem_post(&empty); srand((int)time(NULL)*(int)tid); sleep(1); } return ((void*)0); } //生产者代码 void *producer_thread(void *tid) { int i; pthread_setcancelstate(PTHREAD_CANCEL_ENABLE,NULL); while(1) { sem_wait(&empty); srand((int)time(NULL)*(int)tid); sleep(1); while((nextp+1)%20==nextc); sem_wait(&mutex); if(NUM>20) NUM=1;//如果大于20,NUM重新为1 buffer[nextp]=(NUM++); nextp=(nextp+1)%20; if(nextp==0) { printf("生产者标识:%d\指针位置:19\\\n",(int)tid); } else { printf("生产者标识:%d\指针位置:%d\\\n",(int)tid,nextp-1); } printf("缓冲区:"); for(i=0;i printf("%3d",buffer[i]); } printf("\\n"); sem_post(&mutex); sem_post(&full); srand((int)time(NULL)*(int)tid); } return ((void*)0); }
