多线程实现生产者消费者DOC.docx
《多线程实现生产者消费者DOC.docx》由会员分享,可在线阅读,更多相关《多线程实现生产者消费者DOC.docx(15页珍藏版)》请在冰豆网上搜索。
多线程实现生产者消费者DOC
《嵌入式Linux编程》
课程设计
题目:
多线程实现生产者消费者
之间的通信
班级:
计算机应用xxxx班
学号:
12号
姓名:
xx
指导教师:
xxx
日期:
2014.6.23~2014.6.27
一、课程设计说明
生产者-消费者(producer-consumer)问题,也称作有界缓冲区(bounded-buffer)问题,两个进程共享一个公共的固定大小的缓冲区。
其中一个是生产者,用于将消息放入缓冲区;另外一个是消费者,用于从缓冲区中取出消息。
问题出现在当缓冲区已经满了,而此时生产者还想向其中放入一个新的数据项的情形,其解决方法是让生产者此时进行休眠,等待消费者从缓冲区中取走了一个或者多个数据后再去唤醒它。
同样地,当缓冲区已经空了,而消费者还想去取消息,此时也可以让消费者进行休眠,等待生产者放入一个或者多个数据时再唤醒它。
本次课设通过研究Linux的进程机制和信号量实现生产者消费者问题的并发控制。
二、概要设计
本作业是完善课件上的线程综合实例的练习生产者-消费者问题,重构这个程序的框架,完成性能分析,使之进一步理解掌握Linux下线程的同步、通信以及互斥和多线程的安全问题。
一般情况下,解决互斥方法常用信号量和互斥锁,即semaphore和mutex,而解决这个问题,多采用一个类似资源槽的结构,每个槽位标示了指向资源的指针以及该槽位的状态,生产者和消费者互斥查询资源槽,判断是否有产品或者有空位可以生产,然后根据指针进行相应的操作。
同时,为了告诉生产者或者消费者资源槽的情况,还要有一个消息传送机制,无论是管道还是线程通信。
然而,本次试验有几个特殊的要求:
1、循环缓冲。
2、除了stderr,stdout等外,只用小于2个的互斥锁、
3、放弃资源槽分配机制,采用额外的数据结构。
4、生产者一直持续生产,形成生产消费的良性循环。
首先,使用一个互斥锁,意味着资源槽机制就不能使用了。
因为资源槽虽以用一个互斥锁完成,但是需要有额外的通信,如果使用管道通信,则管道也必须是互斥,这就不满足1个互斥锁的要求。
其次,要求生产者一直生产,这就否定了另外一种方法:
消费者、生产者的位置均平等,消费者消费的时候生产者不能生产,生产者生产的时候消费者不能消费。
因此,就需要采用A要求,也就是循环链表的形式。
为了保证互斥要求,需要定义一个数据结构,这个数据结构包含两个指针,一个读一个写,同时有一个资源数目量,告诉生产者和消费者是否可以生产或者消费。
由于该数据结构很小,因而可以对此结构互斥访问。
同时,对于每组数据,都有一个标志位,表示此组数据是否被占用,生产者和消费者均可以先占用此位置然后完成相应的操作。
当消费者互斥访问此结构时,首先判断是否有数据可以取,如果没有,直接等待,若有数据可取,先更改标志位占用此数据,并将资源数目-1。
然后交出互斥,把数据拷贝到自己缓冲区内,清空数据。
当生产者访问时,首先判断有没有空位可以生产,如果没有,直接等待,若有数据可以生产,先判断该位是否被占用,如果没被占用,则占用此位置进行生产。
生产完成后,将占用位改为未占用,同时将资源数目+1。
三、模块设计
采用信号量来解决n个进程的临界区问题,这n个进程共享一个信号量mutex(mutualexclusion),并初始化为1。
利用p,v原语操作结合信号量实现生产者和消费者进程对缓冲区的互斥访问。
3.1生产者进程
if(fork()==0)
{
inti=0;
while(i<100)
{
semop(emptyid,&P,1);
semop(mutxid,&P,1);
array[*(set)%MAXSEM]=i+1;
printf("Producer%d\n",array[(*set)%MAXSEM]);
(*set)++;
semop(mutxid,&V,1);
semop(fullid,&V,1);
i++;
}//endofwhileinline62
sleep(10);
printf("Producerisover");
exit(0);
图3-1
}
3.2消费者进程
//消费者A进程
if(fork()==0)
{
while
(1)
{
semop(fullid,&P,1);
semop(mutxid,&P,1);
if(*get==100)
break;
*sum+=array[(*get)%MAXSEM];
printf("TheComsumerAGetNumber%d\n",array[(*get)%MAXSEM]);
(*get)++;
if(*get==100)
printf("Thesumis%d\n",*sum);
semop(mutxid,&V,1);
semop(emptyid,&V,1);
图3-2
sleep
(1);
}//endofwhile
(1)inline82
printf("ConsumerAisover");
exit(0);
}//endofifinline81
else
{//消费者B进程
if(fork()==0)
{
while
(1)
{
semop(fullid,&P,1);
semop(mutxid,&P,1);
if(*get==100)
break;
*sum+=array[(*get)%MAXSEM];
printf("TheComsumerBGetNumber%d\n",array[(*get)%MAXSEM]);
(*get)++;
if(*get==100)
printf("Thesumis%d\n",*sum);
semop(mutxid,&V,1);
semop(emptyid,&V,1);
sleep
(1);
}//endofwhile
(1)inline105
printf("ConsumerBisover");
exit(0);
}//endofifinline103
}//endofelseinline101
}
四、详细设计
一、主函数
图4-1
二、统计线程
图4-2
三、生产者线程
图4-3
四、消费者线程
图4-4
五、程序调试
5.1调试记录
有三个warning:
图5-1-1
图5-1-2
图5-1-3
5.2运行结果
图5-2-1
图5-2-2
六、总结
在这次的课程设计中,我遇到了很大的困难,对一些概念很不理解,不过通过和同学交流又上网查阅资料很好的解决了问题,让我在这个过程中学到很多东西,也进一步理解操作系统的概念,同时对Linux编程也有了更多的学习。
这个课程设计并不是很完美,但是起码能让我们很好的理解了什么是生产者—消费者问题。
让我对互斥问题有了更深的见解,同时也认识的到自己很大的不足,在以后的学习中会加以克服,增强自己的问题分析能力和动手实践能力。
虽然实验以前我已经对信号量机制解决进程间同步问题的原理有了很清楚的认识,但是此次课程设计中仍然遇到了很多问题,如Linux系统下各种系统调用以及函数的各种参数,都花费了我很多时间去网上看各种资料——虽然Linux系统中可以很方便的阅读源代码以及使用man命令进行相应指令的查看,但是全英文的资料让人看了不免有些发怵,看来还要多多加强计算机专业英语的学习,以后便可以在Linux系统中查看各种帮助文件。
另一个问题就是在编译的时候遇到的,刚开始用gcc–omainmain.c进行编译的时候总是提示出错,后来查了相关资料才知道pthread库不是Linux系统默认的库,连接时需要使用静态库libpthread.a,所以在使用pthread_create()等函数时,需要链接该库才能编译通过。
以前再用WindowsIDE进行编程的时候基本上不会遇到这样的问题,看来的确IDE为我们做了很多工作,隐藏了一些技术细节,有时候隐藏这些细节虽然可以方便我们,却让我们离真相越来越远。
最近使用Linux进行相关的编程操作,感悟还是挺多的。
Windows下的层层封装的确让我们感到很方便,但同时也让我们编程变得越来越不灵活。
因为我们不用再去了解底层的东西因此一遇到问题就会束手无策。
这段时间一直用Linux进行编程,感觉很方便,跟我以前想象地完全不一样,而且我掌握了不少命令,比我以前用鼠标操作的时候快多了,而且在Bash下可以用Ctrl+Z随时中止正在运行的进程或命令,再用fg%id重新运行。
Linux下的编程也很方便,我还了解了Makefile的编写方法,在多文件编程的时候可以极高地提高效率。
总之,我之后会加强专业英语的学习,以便更好的利用Linux操作系统进行编程之路的学习。
七、参考文献
[1]《OperatingSystemConcepts(SixthEdition)(操作系统概念)影印版》AbrahamSilberschatz编高等教育出版社2003年
[2]《操作系统》罗宇邹鹏吴刚等编著电子工业出版社2006年
[2]《计算机操作系统教程(第三版)》张尧学编清华大学出版社2001年
[3]《计算机操作系统第三版》汤晓丹梁红兵哲凤屛汤子瀛编著西安电子科技大学出版社2009年
[4]《操作系统原理(第三版)》庞丽萍华中科技大学出版社2000年
八、附录
#include
#include
#include
#include
#include
#include
#include
#include
#defineMAXSEM5
////声明三个信号灯ID
intfullid;
intemptyid;
intmutxid;
intmain()
{
structsembufP,V;;
unionsemunarg;
//声明共享内存
int*array;
int*sum;
int*set;
int*get;
//映射共享内存
array=(int*)mmap(NULL,sizeof(int)*5,PROT_READ|PROT_WRITE,MAP_SHARED|MAP_ANONYMOUS,-1,0);
sum=(int*)mmap(NULL,zeof(int),PROT_READ|PROT_WRITE,
MAP_SHARED|MAP_ANONYMOUS,-1,0);
get=(int*)mmap(NULL,sizeof(int),PROT_READ|PROT_WRITE,MAP_SHARED|MAP_ANONYMOUS,-1,0);
set=(int*)mmap(NULL,sizeof(int),PROT_READ|PROT_WRITE,MAP_SHARED|MAP_ANONYMOUS,-1,0);
*sum=0;
*get=0;
*set