ARM多线程应用程序设计实验报告_第1页
ARM多线程应用程序设计实验报告_第2页
ARM多线程应用程序设计实验报告_第3页
ARM多线程应用程序设计实验报告_第4页
ARM多线程应用程序设计实验报告_第5页
已阅读5页,还剩16页未读 继续免费阅读

付费下载

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

1、开放性实验报告基于ARM勺多线程应用程序设计院系名称:电气工程学院专业班级:自动1302学生姓名:蒋贤坤学 号:201323020217指导教师:张晓东成绩:指导老师签名:系统概况 完成步骤2.1思路分析2.2结构流程图2.3重要函数2.3.1源程序2.3.2函数分析实验数据3.1下载和调试截图结果分析和总结设计心得参考文献11111215161系统概况生产者-消费者问题是一个经典的线程同步问题,该问题最早由Dijkstra提出,用以演示他提出的信号量机制。在同一个线程地址空间内执行的两个线程。生产者 线程生产物品,然后将物品放置在一个空缓冲区中供消费者线程消费。消费者线程从缓冲区中获得物品,

2、然后释放缓冲区。当生产者线程生产物品时,如果没有空缓 冲区可用,那么生产者线程必须等待消费者线程释放出一个空缓冲区。当消费者线 程消费物品时,如果没有满的缓冲区,那么消费者线程将被阻塞,直到新的物品被 生产出来。多个生产/消费者在有界缓冲上操作。它利用N个字节的共享内存作为有界循环 缓冲区,利用写一字符模拟放一个产品,利用读一字符模拟消费一个产品。当缓冲 区空时消费者应阻塞睡眠,而当缓冲区满时生产者应当阻塞睡眠。一旦缓冲区中有 空单元,生产者线程就向空单元中入写字符,并报告写的内容和位置。一旦缓冲区中 有未读过的字符,消费者线程就从该单元中读出字符,并报告读取位置。生产者不 能向同一单元中连续

3、写两次以上相同的字符,消费者也不能从同一单元中连续读两 次以上相同的字符。2完成步骤2.1思路分析本试验是练习生产者-消费者问题,成性能分析,使理解掌握线程的同步、通信 以及互斥和多线程的安全问题。一般情况下,解决互斥方法常用信号量和互斥锁, 即semaphore和mutex,而解 决这个问题,多采用一个类似资源槽的结构,每个槽位标示了指向资源的指针以及 该槽位的状态,生产者和消费者互斥查询资源槽,判断是否有产品或者有空位可以 生产,然后进行相应的操作。同时,为了告诉生产者或者消费者资源槽的情况,还 要有一个消息传送机制,无论是管道还是线程通信。为了保证互斥要求,需要定义一个数据结构,这个数据

4、结构包含两个指针,一 个读一个写,同时有一个资源数目量,告诉生产者和消费者是否可以生产或者消费。由于该数据结构很小,因而可以对此结构互斥访问。同时,对于每组数据,都有一个标志位,表示此组数据是否被占用,生产者和消费者均可以先占用此位置然后完成相应的操作。当消费者互斥访问此结构时,首先判断是否有数据可以取,如果没有,直接等 待,若有数据可取,先更改标志位占用此数据,并将资源数目-1o然后交出互斥,把数据拷贝到自己缓冲区内,清空数据。当生产者访问时,首先判断有没有空位可以生产,如果没有,直接等待,若有数据可以生产,先判断该位是否被占用,如果没被占用,则占用此位置进行生产。生产完成后,将占用位改为未

5、占用,同时将资源数目+1 02.2结构流程图试验为生产者-消费者问题模型的实现,主程序中分别启动生产者线程和消费者线程。生产者线程不断顺序地将 0到9的数字写入共享的循环缓冲区,同时消费者线程不断地从共享的循环缓冲区读取数据。试验流程图如下:初始化结构体pthread 中的各个参数建立生产者、消费 者线程等待线程结束退出图2-1结构流程图2.3重要函数2.3.1源程序试验代码:/*main e*/ #in elude "p roducer.h" #in elude "customer.h" #in elude "data.h" #in

6、 elude vp thread.h> #in elude <stdio.h> /*实现生产者线程生产数据放入一个单向链表中,消费者线程负责消费数据*int mai n()p threadthread_ pro;p threadthread_e ons;prin tf("create.n");创建生产者线程。pthread_ereate(&thread _p ro,NULL,(void *)p roducer,NULL);创建消费者线程。pthread_ereate(&thread_c on s,NULL,(void *)eustomer,

7、NULL);prin tf("fi ni shed!n");while(1)return 0;/*data h*/ #ifndef DATA_H_ #defi ne DATA_H_单向链表数据结构struct p roductstruct p roduct *pre_p roduct;char p roduct_data20;struct p roduct *n ext_ product;;/向单向链表中加入一个节点(生产)。void add Product(char *p roduct_data);从单向链表中取出全部节点信息(消费)。void consP roduct(

8、);#en dif /*data c*/ #in clude "data.h" #i nclude <stdio.h> #in clude <stdlib.h> #i nclude <stri ng.h> struct p roduct *p rese nt_p roduct=NULL;struct p roduct *pre_p roduct = NULL;in t lock=0;void add Product(char *p roduct_data)while(lock=1);lock=1;struct p roduct *new_

9、p roduct=malloc(sizeof(struct p roduct);if(p rese nt_p roduct=NULL)new_p roduct-> pre_p roduct=NULL;strc py( new_p roduct- >p roduct_data, product_data);new_p roduct- >n ext_ product=NULL;p rese nt_p roduct=new_p roduct;elsenew_p roduct- >pre_p roduct=p rese nt_p roduct;strc py( new_p ro

10、duct- >p roduct_data, product_data);new_p roduct-> next_ product=NULL;p rese nt_p roduct ->n ext_ product=new_p roduct;p rese nt_p roduct=new_p roduct;lock=0;void consP roduct()while(lock=1);lock=1;while( prese nt_p roduct!=NULL)pre_p roduct=p rese nt_p roduct-> pre_p roduct;prin tf(&quo

11、t;%sn",p rese nt_p roduct- >p roduct_data);if(pre_p roduct!=NULL)pre_p roduct ->n ext_ product=0;free( prese nt_p roduct);p rese nt_p roduct=pre_p roduct;lock=0;/*producer h*/ #ifndef P RODUCER_H_ #define PRODUCER H/生产者执行生产任务 void p roducer();#e ndif /* pr oducer c*/ #in clude "p rod

12、ucer.h" #in clude "data.h" #in clude <stdio.h>#i nclude <stri ng.h> #in elude <stdlib.h> int temp_i=O;void p roducer()char temp 20=0;while(1)sprintf(temp,”number%d",temp_i);add Product(te mp);temp_i+;uslee p(i nt)(ra nd()/2000);/*customerh*/ #ifndef CUSTOMER_H_

13、#define CUSTOMER H/消费者执行消费任务。void customer。;#en dif /*customer c*/ #in clude "customer.h" #in clude "data.h" #in clude <stdlib.h> #in clude <stdio.h> void customer()while(1)consP roduct();n");printf("uslee p(i nt)(ra nd()/1000);int main (i nt argc, char *arg

14、v)p threadp roducer_id;p thread_t con sumer_id;pthread_create(&p roducer_id, NULL, p roducer, NULL);void *p roducer(void *arg) pthread_detach( pthread_self();while(1)pthread_mutex_lock(&m utex);if (size = MALE_LENGTH)prin tf(" person:buff is full( producer)' n");p roducer_wait

15、= 1;p thread_c on d_wait(&full_co nd, & mutex);p roducer_wait = 0;rear = (rear + 1) % MALE_LENGTH;buffrear = ran d() % MALE_LENGTH;prin tf(" producer: %d: %dn", rear, buffrear);+size;if (size = 1)while (1)if (con sumer_wait)pthread_c on d_sig nal(&empty_con d);break;pthread_mut

16、ex_ un lock(&mutex);pthread_create(&con sumer_id, NULL, con sumer, NULL);void *con sumer(void *arg) pthread_detach( pthread_self();while(1)pthread_mutex_lock(&m utex);if(size = 0)prin tf(" person:buff is emp ty(c on sumer)n");con sumer_wait = 1;pthread_c on d_wait(&emp ty_c

17、o nd, & mutex);con sumer_wait = 0;prin tf("c on sumer:%d: %dn", front, bufffr on t);front = (front + 1) % MALE_LENGTH;-size;if (size = MALE_LENGTH-1)while(1)if(p roducer_wait)pthread_c on d_sig nal(&full_co nd);break;pthread_mutex_ un lock(&mutex);slee p(1);return 0;232函数分析生产者写

18、入缓冲区和消费者从缓冲区读数的具体流程,生产者首先要获得互斥锁,并且判断资源槽是否已满,如果资源槽已满则进入等待状态,等待信号full ;如果不满则向资源槽中写一个整数,并且释放信号为emp ty,最后释放互斥锁。消费者线程与生产者线程类似,流程图如下:获得互斥锁获得互斥锁V资源槽满资源槽满等待激活信号full cond等待激活信号empty cond写入数据读取数据激活消费者信号empty cond激活生产者信号full cond4释放互斥锁释放互斥锁1资源槽是否有 数据.r否”否X否”资源槽是否有IJ 数据图2-2生产消费流程图1)生产者写入共享的循环缓冲区入口函数首先我们需要线程分离,调

19、用 P thread_detach(即卩可,线程分离是不让其他线程等待,继续运行。在主循环中我们需要给资源槽上锁,不让消费者函数访问,然后判断资源槽是否满,若为满就解锁资源槽,然后等待消费者激活信号full _cond到来。若没满就增加一个数值给资源槽,然后判断资源槽是否有数据,若有就激活消费者信号empty_cond来消费。void *p roducer(void *arg) pthread_detach( pthread_self();while(1)pthread_mutex_lock(&m utex);if (size = MALE_LENGTH)prin tf("

20、person:buff is full( producer)' n");p roducer_wait = 1;p thread_c on d_wait(&full_co nd, & mutex);p roducer_wait = 0;rear = (rear + 1) % MALE_LENGTH;buffrear = ran d() % MALE_LENGTH;prin tf(" producer: %d: %dn", rear, buffrear);+size;if (size = 1)while (1)if (con sumer_wai

21、t)pthread_c on d_sig nal(&empty_con d);break;pthread_mutex_ un lock(&mutex);2)消费者读取共享的循环缓冲区函数 GET首先需要线程分离,调用P thread_detach(即可。在主循环中我们需要给资源槽上锁,不让生产者函数访问,然后判断资源槽是否满,若不满就解锁资源槽,然后等待消生产者激活信号empty _cond到来。若满就读取一个数值,然后判断资源槽是否有数据,若无就激活生产者信号full_cond来生产。void *con sumer(void *arg) pthread_detach( pth

22、read_self();while(1)pthread_mutex_lock(&m utex);if(size = 0)prin tf(" person:buff is emp ty(c on sumer)n");con sumer_wait = 1;pthread_c on d_wait(&emp ty_co nd, & mutex);con sumer_wait = 0;prin tf("co nsumer:%d: %dn", front, bufffro nt);front = (front + 1) % MALE_LENG

23、TH;-size;if (size = MALE_LENGTH-1)while(1)if(p roducer_wait)pthread_c on d_sig nal(&full_co nd);break;pthread_mutex_ un lock(&mutex);3实验数据3.1下载和调试截图首先进入目录 /mnt/hgfs/share/JXK,然后输入命令gcc xiankun-j.c -o xiankun-j.exe -lpthread编译代码,之后运行可执行文件./xiankun-j.exe,运行结果如图3.1所示。£|Centos CentO5:/mnt/h

24、gfs/share/JXK01; 5 1: 1 2: 03: 74: 75: 4e; 57: 48: 1g: 1交件(E)嘉辑(E)査看世)摟索线端任)諾助血) 蒋贤坤:buff IS fuU(producer) 蒋贤坤-J消费者;0: 9 蒋贤坤"消费者:1: 2 蒋贤坤前肖费者:2: 4 蒋贤坤肖费者汩:5 将贤坤-淖肖费者:4: 0 蒋贤坤-冲肖费者;5: 4 蒋贤坤A消费者淖;3 蒋贤坤消费者:7i 9 蒋贤坤淨消费看:G: 6 蒋贤坤消费者:9: 8 蒋 贤坤:buff is emptyUonsumer) 蒋贤坤产者: 蒋贤坤吐产肴: 蒋贤坤生产者: 蒋贤坤生产者: 蒋贤坤

25、珪产者: 蒋肾坤-洼产者: 蒋贤坤产者: 蒋贤坤产者: 蒋贤坤"生产者: 蒋贤坤生产者:图3.14结果分析和总结1、具体应用情况生产者-消费者是一个很广泛的问题,代表了多线程互斥访问共享资源,以及线 程之间通信的各种问题的总和。这个可以从数据看出,简单有无等待的设置,可以 让数据差异变的如此明显。毕竟,在实际应用中,生产者如何生产数据,产生怎样 的数据,而消费者又如何拿到数据,是通过管道还是内存共享区,拿到数据之后, 是进行处理还是写入磁盘,都有可能,因而,简单通过几组数据来判断哪个进程的 效率更高,是不科学的。我们可以通过两个实际的例子来解释有无等待的情况。有等待更像是在火锅店 吃

26、火锅,商家只要把锅准备好,将生菜切好端上来即可,而顾客大量的时间用在食用上,等待的时间也很少,这样资源位置会大量被消耗,但是实际资源消耗的速度很慢,但是由于空间被占用,生产者无法继续生产。而无等待更像是快餐外卖,商家花大量时间将食物准备好,而消费者只需要交钱拿东西走人即可,资源位置空闲很多,消费者等待时间较长,但是处理数据的过程简单又节约资源。这里还有一个问题,就是资源槽的数量,理论上这个方案应该放弃资源槽,但 是从实际实现方法来看,只不过将每个资源槽的标志位移动到资源内部,然后通过读写指针进行查询,实际上这还是资源槽的变相实现方式。但是单就资源槽的数目来看,是个很复杂的问题,要保证在生产者想

27、生产的时候不会没槽位,而消费者查 询资源槽状态又不会花费太长时间,这需要具体分析每个函数执行的时间,因而本 实验中只是简单设计为消费者数量的1-3倍。2、线程的调度情况首先要考虑的是线程的调度顺序。为了方便起见,每个线程在产生的时候都有 一个编号,而创建也是按照1-Count这样的顺序for循环创建的。如果线程调度的顺 序和线程创建的顺序一样,那么在无等待情况下应该有这样的结果:消费者远多于 生产者,这样当生产者生产出数据时,前面几个优先完成等待并读取数据的进程就 可以占据先机,拿到数据(这里不考虑数据消费的时间,因为程序的思路和食堂占 座差不多,只要把位置占掉就可以了),而后面一些进程则由于

28、位置不佳基本拿不 到数据。当然,插入等待时间也是一种解决资源分配的方式,这样可以保证每个线程都 有机会获取到资源,不至于让某个线程连续的占用资源很长时间。但是在实际情况 下,每个线程完成工作不一样,又不可能像实验写出的进程那样无私,拿到资源后 就自动等待,这就需要使用线程间通信机制了,让拿不到资源的线程挂起,生产者 完成生产后再唤醒这些进程。3、可能的改进首先,就是线程调度的方式,忙等肯定不是一个好方法,如果换成线程间通信, 轮流挂起或者唤醒某个线程,可能会更好。其次,是消费者的资源分配问题。程序设计的消费者有一个1024字节的buffer,用来处理接收到的数据,但是这个buffer直到线程消

29、失才被回收,如果加上一些资源回收的机制可能会改善程序的性能。最后,是对于生产者和消费者具体完成工作的问题,应该说这个实验设计的场 景还是很简单,完全的内存拷贝,没有什么复杂运算和文件操作,而且由于手头没 有原始版本的代码,无法比较两个代码的性能,整个程序的框架也是重新编写的, 这应该也是一点不足。通过这次试验的练习,我对线程、进程等知识有了更直观深入的了解,同时也深感开发程序的不易,通过写这几个程序,发现最常见的运行错误莫过于“段错误”, 这个错误的范围很广,从访问越界,到数组上下限错误,再到内存或者堆栈溢出, 都可能触发这个错误,而如果没有一定的经验这是相当棘手的问题。当然,这个综 合练习实验有很好的价值,除了涉及多个知识点之外,自己在做程序的时候也通过 解

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论