
课程设计报告书
课程名称: 操作系统原理
题 目:用多线程同步方法解决生产者-消费者问题
系 名: 信息工程系
专业班级:
姓 名:
学 号:
指导教师:
年 月 日
课程设计任务书
学生姓名: 专业班级:
指导教师: 工作单位:
设计题目:用多线程同步方法解决生产者-消费者问题
初始条件:
Linux操作系统,GCC编译环境
要求完成的主要任务:
主要任务:
通过研究Linux的线程机制和信号量实现生产者消费者问题的并发控制。
有界缓冲区内设有20个存储单元,放入/取出的数据项设定为1~20这20个整型数。
(1)每个生产者和消费者对有界缓冲区进行操作后,即时显示有界缓冲区的全部内容、当前指针位置和生产者/消费者线程的标识符。
(2)生产者和消费者各有两个以上。
(3)多个生产者或多个消费者之间须共享对缓冲区进行操作的函数代码。
提示:
(1)有界缓冲区/连续存储区可用数组实现。
(2)编译命令可用:
gcc -lpthread -o 目标文件名 源文件名
(3)多线程编程方法参见电子文档。
设计报告撰写格式要求:
1设计题目与要求 2 设计思想
3系统结构 4 数据结构的说明和模块的算法流程图
5 使用说明书(即用户手册):内容包含如何登录、退出、读、写等操作说明
6 运行结果和结果分析(其中包括实验的检查结果、程序的运行情况)
7 自我评价与总结
8 附录:程序清单,注意加注释(包括关键字、方法、变量等),在每个模块前加注释;时间安排
6月 20日 布置课程设计任务;分配题目后,查阅资料、 准备程序;
6月 21 ~6月23 日上机调试程序、书写课程设计报告;
6月24 日 提交课程设计报告及相关文档。
指 导 教 师 签 字: 2011年 6月18日
系 主 任 签 字: 2011年 6月 19日
1.设计目的与要求
1.1设计目的
通过研究Linux的线程机制和信号量实现生产者消费者问题(Producer-Consumer Problem)的并发控制。
1.2设计要求
1)为每个生产者/消费者产生一个线程,设计正确的同步算法
2)每个生产者/消费者对该存储区进行操作后,即时显示该存储区的全部内容、当
前指针位置和生产者/消费者线程的自定义标识符。
3)生产者和消费者各有两个以上。
4)多个生产者/消费者之间须共享对存储区进行操作的函数代码。
2.设计思想及系统平台
2.1设计思想
在本问题中,共需要一个Mutex和两个Semaphore.
其中,Mutex是用来锁定临界区的,以解决对共享数据buffer的互斥访问问题(无论是对生成者还是对消费者);
我们共需要两个Semaphore,这是因为在本问题有两个稀缺资源.
第一种是"非空"这种资源,是在消费者之间进行竞争的.
第二种是"非满"这种资源,是在生产者之间进行竞争的.
所以,一般来说,需要锁定临界区,就需要Mutex;有几种稀缺资源就需要几个Semaphore.
对稀缺资源的分析不能想当然.稀缺资源不一定是指被共享的资源,很多时候是指线程会被阻塞的条件(除了要进临界区被阻塞外).
在生产者消费者问题中,消费者会在缓冲区为空时被阻塞,所以"非空"是一种稀缺资源;
需要设置一个信号量consumer_semaphore,初值设为0;
生产者会在缓冲区为满时被阻塞,所以"非满"也是一种稀缺资源.
需要设置一个信号量producer_semaphore,初值设为buffer的大小MAX_BUFFER
2.2系统平台及使用语言
本课程设计在Linux操作系统下,使用C语言完成。用到的工具主要有GCC编译器和VI编辑器。
3.详细算法描述
共享数据:
Semaphore buffer_mutex=1;
Semaphore producer_semaphore=MAX_BUFFER;
Semaphore consumer_semaphore=0;
int buffer[MAX_BUFFER];
Producer线程的处理函数:
while(1){
Wait(producer_semaphore);
Wait(buffer_mutex);
Buffer[pn]=product;
pn=(pn+1)%MAX_BUFFER;
Signal(consumer_semaphore);
Signal(buffer_mutex);
Sleep();
}
producer线程的处理函数流程图如下:
consumer线程的处理函数:
while(1){
Wait(consumer_semaphore);
Wait(buffer_mutex);
Consume=buffer[cn];
cn=(cn+1)%MAX_BUFFER;
Signal(producer_semaphore);
Signal(buffer_mutex);
Sleep();
}
consumer线程的处理函数流程图如下:
4.源程序清单(注释是后加上的)
用户名:rj070126(IP:192.168.2.254)
源程序名:/home/rj070126/pc.c
目标程序名:/home/rj070126/pc
运行结果:/home/rj070126/output.txt
源程序清单如下:
#include #include #include #include #include #include #include #include #include #include #define NUM_THREADS_P 5 /*定义数据为生产者*/ #define NUM_THREADS_C 5 /*定义数据为消费者*/ #define MAX_BUFFER 20 /*定义数据为缓存区*/ #define RUN_TIME 20 /*定义运行时间*/ int buffer[MAX_BUFFER]; int produce_pointer=0,consume_pointer=0; sem_t producer_semaphore,consumer_semaphore,buffer_mutex; pthread_t threads_p[NUM_THREADS_P]; /*声明生产者线程*/ pthread_t threads_c[NUM_THREADS_C]; /*声明消费者线程*/ FILE* fd; void *producer_thread(void *tid); void *consumer_thread(void *tid); void showbuf(); void handler(){ int i; for(i=0;i for(i=0;i } int main(){ int i; signal(SIGALRM,handler); fd=fopen("output.txt打开一个文件用来保存结果*/ sem_init(&producer_semaphore,0,MAX_BUFFER); /*放一个值给信号灯*/ sem_init(&consumer_semaphore,0,0); sem_init(&buffer_mutex,0,1); for(i=0;i /*创建线程*/ for(i=0;i for(i=0;i alarm(RUN_TIME); /*等待线程退出*/ for(i=0;i for(i=0;i /*清除信号灯*/ sem_destroy(&producer_semaphore); sem_destroy(&consumer_semaphore); sem_destroy(&buffer_mutex); fclose(fd); return 0; } void *producer_thread(void *tid){ pthread_setcancelstate(PTHREAD_CANCEL_ENABLE,NULL); while(1){ sem_wait(&producer_semaphore); srand((int)time(NULL)*(int)tid); sleep(rand()%2+1); /*一个或两个需要生产*/ while((produce_pointer+1)%20==consume_pointer); sem_wait(&buffer_mutex); buffer[produce_pointer]=rand()%20+1; produce_pointer=(produce_pointer+1)%20; if(produce_pointer==0){ printf("producer:%d pointer_p:%2d produced:%2d\\n",(int)tid,19,buffer[19]); fprintf(fd,"producer:%d pointer_p:%2d produced:%2d\\n",(int)tid,19,buffer[19]); } else{ printf("producer:%d pointer_p:%2d produced:%2d\\n",(int)tid,produce_pointer-1,buffer[produce_pointer-1]); fprintf(fd,"producer:%d pointer_p:%2d produced:%2d\\n",(int)tid,produce_pointer-1,buffer[produce_pointer-1]); } showbuf(); sem_post(&buffer_mutex); sem_post(&consumer_semaphore); /*通知消费者缓冲区不是空的*/ srand((int)time(NULL)*(int)tid); sleep(rand()%5+1); /*等待几秒钟,然后继续生产*/ } return ((void*)0); } void *consumer_thread(void *tid){ /*可以被其他线程使用*/ pthread_setcancelstate(PTHREAD_CANCEL_ENABLE,NULL); while(1){ sem_wait(&consumer_semaphore); srand((int)time(NULL)*(int)tid); sleep(rand()%2+1); /*一个或两个来消费*/ sem_wait(&buffer_mutex); printf("consumer:%d pointer_c:%2d consumed:%2d\\n",(int)tid,consume_pointer,buffer[consume_pointer]); fprintf(fd,"consumer:%d pointer_c:%2d consumed:%2d\\n",(int)tid,consume_pointer,buffer[consume_pointer]); buffer[consume_pointer]=0; consume_pointer=(consume_pointer+1)%20; showbuf(); sem_post(&buffer_mutex); sem_post(&producer_semaphore); srand((int)time(NULL)*(int)tid); sleep(rand()%5+1); /*等待几秒钟,然后继续消费*/ } return ((void*)0); } /*查看缓冲区内容*/ void showbuf(){ int i; printf("buffer:"); fprintf(fd,"buffer:"); for(i=0;i fprintf(fd,"%2d ",buffer[i]); } printf("\\n\\n"); fprintf(fd,"\\n\\n"); } 5.运行结果与运行情况 程序运行结果如下: producer:1 pointer_p: 0 produced:20 buffer:20 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 producer:3 pointer_p: 1 produced:13 buffer:20 13 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 producer:2 pointer_p: 2 produced: 6 buffer:20 13 6 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 producer:4 pointer_p: 3 produced:14 buffer:20 13 6 14 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 producer:5 pointer_p: 4 produced:20 buffer:20 13 6 14 20 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 consumer:2 pointer_c: 0 consumed:20 buffer: 0 13 6 14 20 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 producer:1 pointer_p: 5 produced:20 buffer: 0 13 6 14 20 20 0 0 0 0 0 0 0 0 0 0 0 0 0 0 consumer:1 pointer_c: 1 consumed:13 buffer: 0 0 6 14 20 20 0 0 0 0 0 0 0 0 0 0 0 0 0 0 consumer:3 pointer_c: 2 consumed: 6 buffer: 0 0 0 14 20 20 0 0 0 0 0 0 0 0 0 0 0 0 0 0 consumer:4 pointer_c: 3 consumed:14 buffer: 0 0 0 0 20 20 0 0 0 0 0 0 0 0 0 0 0 0 0 0 consumer:5 pointer_c: 4 consumed:20 buffer: 0 0 0 0 0 20 0 0 0 0 0 0 0 0 0 0 0 0 0 0 producer:3 pointer_p: 6 produced: 1 buffer: 0 0 0 0 0 20 1 0 0 0 0 0 0 0 0 0 0 0 0 0 producer:2 pointer_p: 7 produced:14 buffer: 0 0 0 0 0 20 1 14 0 0 0 0 0 0 0 0 0 0 0 0 consumer:3 pointer_c: 5 consumed:20 buffer: 0 0 0 0 0 0 1 14 0 0 0 0 0 0 0 0 0 0 0 0 producer:4 pointer_p: 8 produced: 6 buffer: 0 0 0 0 0 0 1 14 6 0 0 0 0 0 0 0 0 0 0 0 consumer:5 pointer_c: 6 consumed: 1 buffer: 0 0 0 0 0 0 0 14 6 0 0 0 0 0 0 0 0 0 0 0 producer:5 pointer_p: 9 produced: 8 buffer: 0 0 0 0 0 0 0 14 6 8 0 0 0 0 0 0 0 0 0 0 consumer:2 pointer_c: 7 consumed:14 buffer: 0 0 0 0 0 0 0 0 6 8 0 0 0 0 0 0 0 0 0 0 consumer:5 pointer_c: 8 consumed: 6 buffer: 0 0 0 0 0 0 0 0 0 8 0 0 0 0 0 0 0 0 0 0 producer:1 pointer_p:10 produced:18 buffer: 0 0 0 0 0 0 0 0 0 8 18 0 0 0 0 0 0 0 0 0 consumer:1 pointer_c: 9 consumed: 8 buffer: 0 0 0 0 0 0 0 0 0 0 18 0 0 0 0 0 0 0 0 0 producer:2 pointer_p:11 produced:10 buffer: 0 0 0 0 0 0 0 0 0 0 18 10 0 0 0 0 0 0 0 0 producer:4 pointer_p:12 produced:10 buffer: 0 0 0 0 0 0 0 0 0 0 18 10 10 0 0 0 0 0 0 0 consumer:4 pointer_c:10 consumed:18 buffer: 0 0 0 0 0 0 0 0 0 0 0 10 10 0 0 0 0 0 0 0 producer:3 pointer_p:13 produced: 3 buffer: 0 0 0 0 0 0 0 0 0 0 0 10 10 3 0 0 0 0 0 0 consumer:3 pointer_c:11 consumed:10 buffer: 0 0 0 0 0 0 0 0 0 0 0 0 10 3 0 0 0 0 0 0 consumer:2 pointer_c:12 consumed:10 buffer: 0 0 0 0 0 0 0 0 0 0 0 0 0 3 0 0 0 0 0 0 producer:1 pointer_p:14 produced: 6 buffer: 0 0 0 0 0 0 0 0 0 0 0 0 0 3 6 0 0 0 0 0 consumer:1 pointer_c:13 consumed: 3 buffer: 0 0 0 0 0 0 0 0 0 0 0 0 0 0 6 0 0 0 0 0 producer:2 pointer_p:15 produced:18 buffer: 0 0 0 0 0 0 0 0 0 0 0 0 0 0 6 18 0 0 0 0 consumer:5 pointer_c:14 consumed: 6 buffer: 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 18 0 0 0 0 producer:1 pointer_p:16 produced: 6 buffer: 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 18 6 0 0 0 producer:3 pointer_p:17 produced:19 buffer: 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 18 6 19 0 0 consumer:1 pointer_c:15 consumed:18 buffer: 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 6 19 0 0 producer:5 pointer_p:18 produced: 7 buffer: 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 6 19 7 0 consumer:3 pointer_c:16 consumed: 6 buffer: 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 19 7 0 producer:4 pointer_p:19 produced:14 buffer: 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 19 7 14 consumer:5 pointer_c:17 consumed:19 buffer: 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 7 14 consumer:4 pointer_c:18 consumed: 7 buffer: 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 14 producer:1 pointer_p: 0 produced: 4 buffer: 4 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 14 consumer:2 pointer_c:19 consumed:14 buffer: 4 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 consumer:1 pointer_c: 0 consumed: 4 buffer: 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 producer:2 pointer_p: 1 produced:15 buffer: 0 15 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 producer:3 pointer_p: 2 produced:13 buffer: 0 15 13 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 producer:2 pointer_p: 3 produced: 3 buffer: 0 15 13 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 说明: “producer:2”是指自定义标号为2的producer,“pointer_p:3”是指该producer的指针,“produced:3”是指该producer在buffer[3]里写入3,“buffer: 0 15 13 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ”是指该producer进行写操作后存储区的内容。 6.调试过程 通过这次课程设计,不但加深了对操作系统这们课程的认识,而且还了解了操作系统中使用信号量解决生产者—消费者问题算法的实现。比如:用信号量解决生产者—消费者问题时,可以通过一个有界缓冲区(用数组来实现,类似循环队列)把生产者和消费者联系起来。假定生产者和消费者的优先级是相同的,只要缓冲区未满,生产者就可以生产产品并将产品送入缓冲区。类似地,只要缓冲区未空,消费者就可以从缓冲区中去走产品并消费它。为了解决生产者/消费者问题,应该设置两个资源信号量,其中一个表示空缓冲区的数目,用producer_semaphore表示,其初始值为有界缓冲区的大小SIZE_OF_BUFFER;另一个表示缓冲区中产品的数目,用consumer_semaphore表示,其初始值为0。另外,由于有界缓冲区是一个临界资源,必须互斥使用,所以还需要再设置一个互斥信号量buffer_mutex,起初值为1。在生产者/消费者问题中,信号量实现两种功能。首先,它是生产产品和消费产品的计数器,计数器的初始值是可利用的资源数 目(有界缓冲区的长度)。其次,它是确保产品的生产者和消费者之间动作同步的同步器。生产者要生产一个产品时,首先对资源信号量producer_semaphore和互斥信号量buffer_mutex进行wait操作,申请资源。如果可以通过的话,就生产一个产品,并把产品送入缓冲区。然后对互斥信号量buffer_mutex和资源信号量consumer_semaphore进行signal操作,释放资源。消费者要消费一个产品时,首先对资源信号量consumer_semaphore和互斥信号量buffer_mutex进行wait操作,申请资源。如果可以通过的话,就从缓冲区取出一个产品 并消费掉。然后对互斥信号量buffer_mutex和资源信号量producer_semaphore进行signal操作,释放资源。 7.总结 通过本次课程设计,我巩固了使用多线程编程的方法,和使用信号量同步进/线程的技巧。本次课程设计的程序的运行结果跟预期的一致,说明该程序能顺利解决生产者消费者问题,实现了本次课程设计的目的。 另外,使我体会最深的是:任何一门知识的掌握,仅靠学习理论知识是远远不够的,要与实际动手操 作相结合才能达到功效。短短的课程设计就要结束了,不但对专业知识有了更深的理解,更使自己认识到 实践的重要性,理论、实践相结合才能达到很好的学习效果,特别是程序语言的学习。 设计过程中质疑(或答辩)记载: 指导教师评语: 签名: 年 月 日{设计报告书中的最后一页}
