用多线程同步方法解决生产者消费者问题.docx
- 文档编号:5194005
- 上传时间:2022-12-13
- 格式:DOCX
- 页数:11
- 大小:74.86KB
用多线程同步方法解决生产者消费者问题.docx
《用多线程同步方法解决生产者消费者问题.docx》由会员分享,可在线阅读,更多相关《用多线程同步方法解决生产者消费者问题.docx(11页珍藏版)》请在冰豆网上搜索。
用多线程同步方法解决生产者消费者问题
1.
需求分析
1.1课程设计题目
用多线程同步方法解决生产者-消费者问题
1.2课程设计任务
(1)每个生产者和消费者对有界缓冲区进行操作后,即时显示有界缓冲区的全部内容、当前指针位置和生产者/消费者线程的标识符。
(2)生产者和消费者各有两个以上。
(3)多个生产者或多个消费者之间须共享对缓冲区进行操作的函数代码。
1.3课程设计原理
生产者和消费者问题是从操作系统中的许多实际同步问题中抽象出来的具有代表
性的问题,它反映了操作系统中典型的同步例子,生产者进程(进程由多个线程组成)生产信息,消费者进程使用信息,由于生产者和消费者彼此独立,且运行速度不确定,所以很可能出现生产者已产生了信息而消费者却没有来得及接受信息这种情况。
为此,需要引入由一个或者若干个存储单元组成的临时存储区(即缓冲区),以便存放生产者所产生的信息,解决平滑进程间由于速度不确定所带来的问题。
1.4课程设计要求
(1)有界缓冲区内设有20个存储单元,放入/取出的数据项设定为1~20这20个整型数。
(2)每个生产者和消费者对有界缓冲区进行操作后,即时显示有界缓冲区的全部内容、当前指针位置和生产者/消费者线程的标识符。
(3)生产者和消费者各有两个以上。
(4)多个生产者或多个消费者之间须共享对缓冲区进行操作的函数代码。
1.5实验环境
系统平台:
LINUX
开发语言:
C
开发工具:
PC机一台
2.概要设计
2.1课程设计方案概述
本设计中设置一个长度为20的一维数组buff[20]作为有界缓冲区,缓冲区为0时,代表该缓冲区内没有产品,buff[i]=i+1表示有产品,产品为i+1。
设置3个同步信号灯:
一个说明空缓冲区的数目,用empty表示,其初值为有界缓冲区的大小20;另一个说明满缓冲区(即产品)的数目,用full表示,其初值为0。
由于缓冲区是临界资源,必须互斥使用,所以还设置了一个互斥信号灯mutex,其初值为1。
用这3个信号灯有效控制多个生产者线程和多个消费者线程的同步准确的运行。
Main()函数中调用函数sem_init()对信号灯进行初始化;利用for语句循环创建5个producer(生产者)分离线程和5个consumer(消费者)分离线程;Producer线程通过调用函数sem_wait(&empty)判断是否有空缓冲区。
若无,则阻塞当前线程,若有则调用函数sem_wait(&mutex)等待对临界资源的操作权,当mntex为1时,便获得临界资源的操作权,可将产品放入缓冲区,及时输出缓冲区里的内容。
然后依次调用函数sem_post(&mutex)和sem_post(&full)来释放缓冲区操作权和增加满缓冲区信号量的值;Consumer线程通过调用函数sem_wait(&full)判断是否有满缓冲区。
若无,则阻塞当前线程,若有则调用函数sem_wait(&mutex)等待对临界资源的操作权,当mntex为1时,便获得临界资源的操作权,可从满缓冲区中取出产品消费,并及时输出缓冲区里的内容。
然后依次调用函数sem_post(&mutex)和sem_post(&emptyl)来释放缓冲区操作权和增加空满缓冲区信号量的值。
Producer和Consumer线程中均用缓冲区指针b指出当前是对哪一个缓冲区进行放入/取出操作;并调用pthread_self()函数来显示其自身的标识符。
2.2课程设计流程图
设计中主要有三个模块,首先从主程序中进入,完成初始化及创建好生产者和消费者线程后,进入生产者或消费者模块,具体流程见程序设计流程图如图1所示:
图1程序设计流程图
3.详细设计
3.1主程序模块
主程序中利用函数sem_init()对信号灯进行初始化;利用for语句循环创建3个producer(生产者)分离线程和3个consumer(消费者)分离线程,程序段如下:
intmain(void)
{inti;
initbuff();
for(i=0;i<5;i++)
{pthread_create(&id1[i],NULL,(void*)producer,(&i));}//创建生产者线程
for(i=0;i<5;i++)
{pthread_create(&id2[i],NULL,(void*)consumer,(&i));}//创建消费者线程
for(i=0;i<5;i++)
{pthread_join(id1[i],NULL);
pthread_join(id2[i],NULL);}
exit(0);}//等待生产者线程,消费者线程,结束主线程
3.2生产者程序模块
Producer线程通过调用函数sem_wait(&empty)判断是否有空缓冲区。
若无,则阻塞当前线程,若有则调用函数sem_wait(&mutex)等待对临界资源的操作权,当mntex为1时,便获得临界资源的操作权,可将产品放入缓冲区,及时输出缓冲区里的内容;并用指针b指出当前是对哪一个缓冲区进行放入/取出操作,且调用pthread_self()函数来显示其自身的标识符。
然后依次调用函数sem_post(&mutex)和sem_post(&full)来释放缓冲区操作权和增加满缓冲区信号量的值,程序段如下:
voidproducer()//生产者
{intpid=0;
intj,k;
pid=pthread_self();//获得生产者标识符
while
(1)
{for(j=0;j<5;j++)
{if(pid==id1[j])
{k=j+1;}}
sem_wait(&empty);//P操作,判断缓冲区是否有空位置
sem_wait(&mutex);//P操作,获得对临界资源的操作权
if(p%21!
=0)
{buff[b]=p%21;
printf("producer%dproduce:
%d\n",k,p%21);
printbuff();
b++;p++;}
elsep++;
sem_post(&mutex);//V操作,释放临界资源
sem_post(&full);//V操作,满缓冲区信号灯加1
sleep(4);}}
3.3消费者程序模块
Consumer线程调用调用函数sem_wait(&full)判断是否有满缓冲区。
若无,则阻塞当前线程,若有则调用函数sem_wait(&mutex)等待对临界资源的操作权,当mntex为1时,便获得临界资源的操作权,可从满缓冲区中取出产品消费,并及时输出缓冲区里的内容,并用指针b指出当前是对哪一个缓冲区进行放入/取出操作,且调用pthread_self()函数来显示其自身的标识符。
然后依次调用函数sem_post(&mutex)和sem_post(&emptyl)来释放缓冲区操作权和增加空满缓冲区信号量的值,程序段如下:
voidconsumer()//消费者
{intcid=0;
intj,k;
cid=pthread_self();//获得消费者标识符
while
(1)
{for(j=0;j<5;j++)
{if(cid==id2[j])
{k=j+1;}}
sem_wait(&full);//P操作,判断缓冲区是否已满
sem_wait(&mutex);//P操作,获得对临界资源的操作权
if(c%21!
=0)
{c1=buff[b-1];
printf("consumer%dconsume:
%d\n",k,c1);
buff[b-1]=0;
printbuff();
b--;c++;}
elsec++;
sem_post(&mutex);//V操作,释放临界资源
sem_post(&empty);//V操作,释放一个空位置
sleep(6);}
4.调试中遇到的问题及解决方案
在调试过程中主要遇到三个问题:
1.在设计刚完成的时候,我并没有用pid=pthread_self()和cid=pthread_self()来获得生产者和消费者的标识符,所以运行的结果是生产者和消费者的标识符都是随机的,后来问同学才找到这种调用方法。
2.我想让生产者无限的生产,消费者无限的消费,所以就用了一个条件判断语句,判断的条件是p%21!
=0,而我写成了p/21!
=0,所以运行的结果是生产者的生产是混乱的,没有规律。
3.刚开始我的运行结果还有一个问题就是生产者生产超过21的产品后,产品号不是1,2…等,而是21,22,…,后来检查后才发现printf("producer%dproduce:
%d\n",k,p%21)中的产品号不是p%21,所以出现那种情况。
5.运行结果
显示结果如下:
(部分运行结果)
6.实验小结
这次课程设计主要针对的是操作系统中的经典问题即:
生产者——消费者问题使用多线程控制,刚拿到设计题目时心里其实挺没底的,因为之前我对线程不是很了解,不过幸好老师上课的时候给了我们一个关于Linux多线程编程的文档,里面详细的介绍了线程的一些基本命令,所以我在这次设计中基本上都用的是文档里的命令。
从这次课程设计中,我对线程的概念以及一些命令都有了一定的理解和掌握,并且也知道了它与进程之间的区别,除此之外,通过这次课程设计让我对操作系统中的经典问题,生产者——消费者问题有了更深的理解,在做设计的过程中,也对上课的内容加深了理解并进行了巩固。
参考文献
[1]庞丽萍.操作系统原理.华中科技大学出版社.2009年1月。
[2]蒋静徐志伟.操作系统原理技术与编程[M].北京:
机械工业出版社,2004
[3]张红光李福才.UNIX操作系统。
机械工业出版社。
2006年1月
[4]汤子瀛等.计算机操作系统.西安电子科技大学出版社.2001年5月
[5]付国瑜杨武周敏.计算机操作系统原理及应用上机实验指导.重庆工学院计算机学院.2005年1月.
附录:
源程序清单
#include
#include
#include
#include
intbuff[20]={0};//有界缓冲区定义
intb=0;//缓冲区的输出指针
intp=1;
intc=1;
intc1=0;//消费数据变量
sem_tfull;//缓冲区的数量信号灯
sem_tempty;//缓冲区满信号灯
sem_tmutex;//互斥信号灯
pthread_tid1[5];
pthread_tid2[5];
voidinitbuff()//初始化信号灯
{sem_init(&full,0,0);
sem_init(&empty,0,20);
sem_init(&mutex,0,1);//初始化互斥信号灯}
voidprintbuff()//打印缓冲区
{intj;
printf("datasinbuffare:
");
for(j=0;j<20;j++)
printf("%d",buff[j]);
printf("\n");}
voidproducer()//生产者
{intpid=0;
intj,k;
pid=pthread_self();
while
(1)
{for(j=0;j<5;j++)
{if(pid==id1[j])
{k=j+1;}}
sem_wait(&empty);
sem_wait(&mutex);
if(p%21!
=0)
{buff[b]=p%21;
printf("producer%dproduce:
%d\n",k,p%21);
printbuff();
b++;
p++;}
elsep++;
sem_post(&mutex);
sem_post(&full);
sleep(4);}}
voidconsumer()//消费者
{intcid=0;
intj,k;
cid=pthread_self();
while
(1)
{for(j=0;j<5;j++)
{if(cid==id2[j])
{k=j+1;}}
sem_wait(&full);//看是否有数据在缓冲区
sem_wait(&mutex);//临界区
if(c%21!
=0)
{c1=buff[b-1];
printf("consumer%dconsume:
%d\n",k,c1);
buff[b-1]=0;
printbuff();
b--;
c++;}
elsec++;
sem_post(&mutex);
sem_post(&empty);
sleep(6);}}
intmain(void)
{inti;
initbuff();
for(i=0;i<5;i++)
{pthread_create(&id1[i],NULL,(void*)producer,(&i));}//创建生产者线程
for(i=0;i<5;i++)
{pthread_create(&id2[i],NULL,(void*)consumer,(&i));}//创建消费者线程
for(i=0;i<5;i++)
{pthread_join(id1[i],NULL);
pthread_join(id2[i],NULL);}
exit(0);}//等待生产者线程,消费者线程,结束主线程
设计过程中质疑(或答辩)记载:
1.生产者和消费者是如何从缓冲区中存放和读取数据的?
答:
生产者将生产的产品从头到尾存入缓冲区,消费者从缓冲区中最后一个开始读取,即从后往前取。
2.设计中用到的三个信号灯各有什么作用?
答:
信号灯full是用来判断缓冲区中是否已满,如果满了就会发生阻塞,即生产者先暂停生产,信号灯empty是用来判断缓冲区是否还有产品,如果没有,消费者就暂停消费,互斥信号灯mutex是用来对临界资源的操作权进行控制的。
指导教师评语:
签名:
2009年7月03日
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 多线程 同步 方法 解决 生产者 消费者 问题