用多线程同步方法解决生产者-消费者问题
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
目录
1.需求分析 (1)
1.1 课程设计题目 (1)
1.2 课程设计任务 (1)
1.3 课程设计原理 (1)
1.4 课程设计要求 (1)
1.5 实验环境 (1)
2. 概要设计 (2)
2.1 课程设计方案概述 (2)
2.2 课程设计流程图 (2)
3.详细设计 (3)
3.1 主程序模块 (3)
3.2 生产者程序模块 (4)
3.3 消费者程序模块 (5)
4.调试中遇到的问题及解决方案 (5)
5.运行结果 (6)
6.实验小结 (7)
参考文献 (7)
附录:源程序清单 (7)
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所示:
生产者消费者
3.详细设计
3.1 主程序模块
主程序中利用函数sem_init()对信号灯进行初始化;利用for语句循环创建3个producer(生产者)分离线程和3个consumer(消费者)分离线程,程序段如下:int main(void)
{ int i;
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)来释放缓冲区操作权和增加满缓冲区信号量的值,程序段如下:
void producer() //生产者
{ int pid=0;
int j,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 %d produce:%d\n",k,p%21);
printbuff();
b++; p++; }
else p++;
sem_post(&mutex); //V操作,释放临界资源