用多线程同步方法解决生产者消费者问题.docx
《用多线程同步方法解决生产者消费者问题.docx》由会员分享,可在线阅读,更多相关《用多线程同步方法解决生产者消费者问题.docx(12页珍藏版)》请在冰豆网上搜索。
![用多线程同步方法解决生产者消费者问题.docx](https://file1.bdocx.com/fileroot1/2023-2/2/60f0e816-f083-4e56-af8d-2bb2baa4d274/60f0e816-f083-4e56-af8d-2bb2baa4d2741.gif)
用多线程同步方法解决生产者消费者问题
武汉理工大学华夏学院
课程设计报告书
课程名称:
操作系统原理
题目:
用多线程同步方法解决生产者-消费者问题
系名:
信息工程系
专业班级:
软件1091班
姓名:
千里锋行
学号:
指导教师:
赵传斌苏永红
2011年12月21日
课程设计任务书
学生姓名:
千里锋行专业班级:
软件1091
指导教师:
苏永红工作单位:
设计题目:
用多线程同步方法解决生产者-消费者问题
初始条件:
1.操作系统:
Linux
2.程序设计语言:
C语言
3.有界缓冲区内设有20个存储单元,其初值为0。
放入/取出的数据项按增序设定为1-20这20个整型数。
要求完成的主要任务:
主要任务:
通过研究Linux的线程机制和信号量实现生产者消费者问题的并发控制。
有界缓冲区内设有20个存储单元,放入/取出的数据项设定为1~20这20个整型数。
(1)每个生产者和消费者对有界缓冲区进行操作后,即时显示有界缓冲区的全部内容、当前指针位置和生产者/消费者线程的标识符。
(2)生产者和消费者各有两个以上。
(3)多个生产者或多个消费者之间须共享对缓冲区进行操作的函数代码。
提示:
(1)有界缓冲区/连续存储区可用数组实现。
(2)编译命令可用:
gcc-lpthread-o 目标文件名 源文件名
(3)多线程编程方法参见电子文档。
设计报告撰写格式要求:
1设计题目与要求2设计思想
3系统结构4数据结构的说明和模块的算法流程图
5使用说明书(即用户手册):
内容包含如何登录、退出、读、写等操作说明
6运行结果和结果分析(其中包括实验的检查结果、程序的运行情况)
7自我评价与总结
8附录:
程序清单,注意加注释(包括关键字、方法、变量等),在每个模块前加注释;时间安排
12月19日布置课程设计任务;分配题目后,查阅资料、准备程序;
12月19~12月21日上机调试程序、书写课程设计报告;
12月22日提交课程设计报告及相关文档。
指导教师签字:
2011年12月17日
系主任签字:
2011年12月18日
一.设计题目与要求
1设计目的
通过研究Linux的线程机制和信号量实现生产者消费者问题(Producer-ConsumerProblem)的并发控制。
2设计要求
1)为每个生产者/消费者产生一个线程,设计正确的同步算法
2)每个生产者/消费者对该存储区进行操作后,即时显示该存储区的全部内容、当
前指针位置和生产者/消费者线程的自定义标识符。
3)生产者和消费者各有两个以上。
4)多个生产者/消费者之间须共享对存储区进行操作的函数代码。
二.设计思想
本次课设涉及到同步信号量和互斥信号量的应用,在这里我用线程的同步和互斥来实现。
在同一个进程地址空间内执行的两个线程。
生产者线程生产物品,然后将物品放置在一个空缓冲区中供消费者线程消费。
消费者线程从缓冲区中获得物品,然后释放缓冲区。
当生产者线程生产物品时,如果没有空缓冲区可用,那么生产者线程必须等待消费者线程释放出一个空缓冲区。
当消费者线程消费物品时,如果没有满的缓冲区,那么消费者线程将被阻塞,直到新的物品被生产出来。
在本问题中,共需要一个Mutex和两个Semaphore,其中Mutex是来用锁定临界区的,以解决对共享数据buffer的互斥访问问题(无论是对生成者还是对消费者);我们共需要两个Semaphore,这是因为在本问题中共有两个稀缺资源.第一种是"非空"这种资源,是在消费者之间进行竞争的;第二种是"非满"这种资源,是在生产者之间进行竞争的.所以,一般来说,需要锁定临界区,就需要Mutex;有几种稀缺资源就需要几个Semaphore.
稀缺资源不一定是指被共享的资源,很多时候是指线程会被阻塞的条件(除了要进临界区被阻塞外).
在生产者消费者问题中,消费者会在缓冲区为空时被阻塞,所以"非空"是一种稀缺资源。
需要设置一个信号量consumer_semaphore,初值设为0,生产者会在缓冲区为满时被阻塞,所以"非满"也是一种稀缺资源.需要设置一个信号量producer_semaphore,初值设为buffer的大小MAX_BUFFER。
三.系统结构
四.数据结构的说明和模块的算法流程图
五.使用说明书
1.宏的意义:
N:
消费者或者生产者的数目
M:
缓冲区的数目
2.程序的运行
a.打开linux的终端;
b.编译程序,输入命令
gcc–odyb–pthread;
./dyb
3.显示结果
程序运行后不需要接受用户输入,直接显示运行结果。
六.运行结果和结果分析
[dj@softeem~]$ls
公共的模板视频图片文档下载音乐桌面
[dj@softeem~]$gcc-odyb-pthread
[dj@softeem~]$./dyb
producer1in0:
10000000000000000000
customer1in0:
00000000000000000000
producer2in1:
01000000000000000000
customer2in1:
00000000000000000000
producer1in2:
00100000000000000000
customer1in2:
00000000000000000000
producer2in3:
00010000000000000000
customer2in3:
00000000000000000000
producer1in4:
00001000000000000000
customer1in4:
00000000000000000000
producer2in5:
00000100000000000000
customer2in5:
00000000000000000000
producer1in6:
00000010000000000000
customer1in6:
00000000000000000000
producer2in7:
00000001000000000000
customer2in7:
00000000000000000000
producer1in8:
00000000100000000000
customer1in8:
00000000000000000000
producer2in9:
00000000010000000000
customer2in9:
00000000000000000000
producer1in10:
00000000001000000000
customer1in10:
00000000000000000000
producer2in11:
00000000000100000000
customer2in11:
00000000000000000000
producer1in12:
00000000000010000000
customer1in12:
00000000000000000000
producer2in13:
00000000000001000000
customer2in13:
00000000000000000000
producer1in14:
00000000000000100000
customer1in14:
00000000000000000000
producer2in15:
00000000000000010000
customer2in15:
00000000000000000000
producer1in16:
00000000000000001000
customer1in16:
00000000000000000000
producer2in17:
00000000000000000100
customer2in17:
00000000000000000000
producer1in18:
00000000000000000010
customer1in18:
00000000000000000000
producer2in19:
00000000000000000001
customer2in19:
00000000000000000000
对于此程序,有20个缓冲区,定义了两个生产者和两个消费者,生产者和消费者是模拟的现实中的生产与消费的关系,生产者生产产品时占用一个线程,消费者取一个产品时启用一个线程,生产产品和消费产品是利用锁来实现的。
但是最后还是有问题没能解决好,就是生产一个消费一个,缓冲区就没有利用好。
七.自我评价与总结
本次课程设计,听了邓君老师几天的讲解,见识到了他的年轻有为,也让自己对IT行业有了更深的向往。
同时也加深了一些对多线程编程方法的理解,和使用信号量同步进/线程的技巧。
上课时看邓老师演示在linux下编写一个多人聊天的小程序,我在下面也跟住做。
几次遇到了问题,老师都及时耐心的给我解决。
最后我也跟着老师敲代码,虽然只是敲代码,不是自己的思想写出来的,但是万事开头难,我觉得只要我动手了,就成功了一半。
在跟着老师做的过程中,我体会到了自己的不足,很多地方都不懂,但是我觉得在这个阶段对一些比较深的东西也不一定要处处都弄懂,有时候子要自己跟着做,会用,久而久之也会随着经验的加深而慢慢弄懂,这虽然是一种不求甚解的态度,但在初级编程中往往是很有用的。
本次课程设计的程序更具要求定义了20个缓冲区,基本上能顺利解决生产者消费者问题,但也存在很多不足之处。
因为程序都是根据别人的来的,所以往往想加入自己的想法,比如随机函数解决随机的问题时遇到障碍,最后由于出现的错误太多,时间不够,所以只得放弃,只能在一些小的边边角角上稍加改动,试着去体会这个程序的思想。
设计过程中质疑(或答辩)记载:
1.谈谈你对多线程的理解。
答:
在一个程序中,独立运行的程序片断叫作“线程”(Thread),利用它编程的概念就叫作“多线程处理”。
多线程是为了同步完成多项任务,不是为了提高运行效率,而是为了提高资源使用效率来提高系统的效率。
线程是在同一时间需要完成多项任务的时候实现的。
2.此程序的不足之处
答:
定义了20个缓冲区,但是每次只利用到1个缓冲区,造成了资源的浪费,没有起到随机的作用。
我曾尝试用随机函数去解决,但是没能成功。
指导教师评语:
签名:
年月日
七.附录
程序清单:
#include<>
#include<>
#include<>
#include<>
#include<>
#defineN2//消费者或者生产者的数目
#defineM20//缓冲数目
intin=0;//生产者放置产品的位置
intout=0;//消费者取产品的位置
intbuff[M]={0};//缓冲初始化为0,开始时没有产品
sem_tempty_sem;//同步信号量,当满了时阻止生产者放产品
sem_tfull_sem;//同步信号量,当没产品时阻止消费者消费
pthread_mutex_tmutex;//互斥信号量,一次只有一个线程访问缓冲
intproduct_id=0;//生产者id
intprochase_id=0;//消费者id
/*打印缓冲情况*/
voidprint()
{
inti;
for(i=0;iprintf("%d",buff[i]);
printf("\n");
}
/*生产者方法*/
void*product()
{
intid=++product_id;
while
(1)
{
//用sleep的数量可以调节生产和消费的速度,便于观察
sleep
(1);
//sleep
(1);
sem_wait(&empty_sem);
pthread_mutex_lock(&mutex);
in=in%M;
printf("producer%din%d:
",id,in);
buff[in]=1;
print();
++in;
pthread_mutex_unlock(&mutex);
sem_post(&full_sem);
}
}
/*消费者方法*/
void*prochase()
{
intid=++prochase_id;
while
(1)
{
//用sleep的数量可以调节生产和消费的速度,便于观察
sleep
(1);
//sleep
(1);
sem_wait(&full_sem);
pthread_mutex_lock(&mutex);
out=out%M;
printf("customer%din%d:
",id,out);
buff[out]=0;
print();
++out;
pthread_mutex_unlock(&mutex);
sem_post(&empty_sem);
}
}
intmain()
{
pthread_tid1[N];
pthread_tid2[N];
inti;
intret[N];
//初始化同步信号量
intini1=sem_init(&empty_sem,0,M);
intini2=sem_init(&full_sem,0,0);
if(ini1&&ini2!
=0)
{
printf("seminitfailed\n");
exit
(1);
}
//初始化互斥信号量
intini3=pthread_mutex_init(&mutex,NULL);
if(ini3!
=0)
{
printf("mutexinitfailed\n");
exit
(1);
}
//创建N个生产者线程
for(i=0;i{
ret[i]=pthread_create(&id1[i],NULL,product,(void*)(&i));
if(ret[i]!
=0)
{
printf("product%dcreationfailed\n",i);
exit
(1);
}
}
//创建N个消费者线程
for(i=0;i{
ret[i]=pthread_create(&id2[i],NULL,prochase,NULL);
if(ret[i]!
=0)
{
printf("prochase%dcreationfailed\n",i);
exit
(1);
}
}
//销毁线程
for(i=0;i{
pthread_join(id1[i],NULL);
pthread_join(id2[i],NULL);
}
exit(0);
}