实验四并行结构实验

整理文档很辛苦,赏杯茶钱您下走!

免费阅读已结束,点击下载阅读编辑剩下 ...

阅读已结束,您可以下载文档离线阅读编辑

资源描述

实验四并行结构实验实验目的观察SMP上多线程并发程序行为;了解并掌握消除SMP上cacheping-pong效应的方法;学习NUMA内存访存特性实验内容以一个计数程序作为起点,先简单并行化,然后修正其并发执行的同步问题、并发度问题、cache的ping-pong效应问题,最后形成一个比较理想的SMP并发程序。第二部分为选做部分,观察NUMA访存性能特性,掌握内存绑定方法。实验环境硬件:PC或任何一款具有cache的功能的计算机软件:Windows/Linux操作系统、C语言编译器实验步骤及相关说明要求学生学习SMP上的pthread库多线程编程,按要求编写程序代码逐步完成实验操作。1)编写一个完整程序用于统计一个数组中“M”字符出现的个数,统计核心样例代码如下:程序一核心统计代码(不含主函数、线程创建代码等)int*array;intlength;intcountintcount3s(){inti;count=0;for(i=0;ilength;i++){if(array[i]==3){count++;}}returncount;}编写完整程序,要求arrary元素足够多,256M以上,初始化为“MPMPMP…”模式。运行后记录执行时间。2)对上述程序完成多线程化的改造,用pthread编写多线程程序,每个线程所执行的统计代码以下列代码为起点:程序二线程化的核心统计代码(不含主函数、线程创建代码等)int*array;//待统计的数组intlength;//每个线程划分到的元素个数intcount;//统计出来的“M”个数intt;//线程数,取值为处理器核数voidcount3s_thread(intid)//id为创建线程时传入的线程号{/*computeportionofthearraythatthisthreadshouldworkon*/intlength_per_thread=length/t;//每个线程分担的元素个数intstart=id*length_per_thread;//本线程负责的数组下标起点for(i=start;istart+length_per_thread;i++)//遍历本线程负责的所有元素{if(array[i]==3){count++;//将总数增1}}}完成主程序设计,将数组array等分为几部分,每个部分由一个线程执行count3s_thread()统计“M”字符的出现次数——保存在count共享变量中,实现多线程并发统计的功能。按1、2、4、8、16个线程数量分别执行,记录各自所需的执行时间(绘制成柱状图)。3)执行上述程序,统计结果是否正确?如果不正确,请加上pthread的互斥锁mutext以解决其错误——每次访问count时先申请mutext,访问结束后释放mutex,从而实现互斥访问保证结果正确;mutexm;…..voidcount3s_thread(intid){/*computeportionofthearrraythatthisthreadshouldworkon*/intlength_per_thread=length/t;intstart=id*length_per_thread;for(i=start;istart+length_per_thread;i++){if(array[i]==3){mutex_lock(m);count++;mutex_unlock(m);}}按照1、2、4、8、16个线程数量运行,记录各自所需的执行时间。4)比较1)、3)的执行时间(绘制成柱状图),分析原因。将代码进一步改造为先将局部统计值记录在私有变量上,最后再统计总数,样例代码如下:private_count[MaxThreads];mutexm;voidcount3s_thread(intid){/*computeportionofarrayforthisthreadtoworkon*/intlength_per_thread=length/t;intstart=id*length_per_thread;for(i=start;istart+length_per_thread;i++){if(array[i]==3){private_count[id]++;}}mutex_lock(m);count+=private_count[id];mutex_unlock(m);}5)比较1)3)4)执行时间,分析结果,参考多核处理器间cache竞争引发的ping-pong效应,尝试消除该效应并检验是否获得性能提升。记录1、2、4、8、16个线程数目下的各自执行时间并与1)的时间相比较(绘制成柱状图)。附:选做实验学习线程和内存在NUMA节点/CPU的绑定编程接口。在NUMA平台上(例如我中心的D1主机)上完成线程与内存的不同绑定模式——本地访问和远程访问,测试各自所获得的内存带宽。实验过程及结果1)编写完成程序如下:#includeiostream#includetime.h#defineN1024*1024*256usingnamespacestd;chararray[N];intcountMs();intmain(){clock_tstart,end;inti;for(i=0;iN;i+=2){array[i]='M';array[i+1]='P';}start=clock();coutcountMs()endl;end=clock();coutTimeisend-startms.endl;return0;}intcountMs(){inti;intcount=0;for(i=0;iN;i++){if(array[i]=='M'){count++;}}returncount;}执行结果:结果分析:该实验为串行实验,数组大小为1024*1024*256,输出M的个数应该为134217728,结果正确,用时638708ms.2)完整代码:#includestdio.h#includetime.h#includepthread.h#includeunistd.h#defineN1024*1024*256//#defineNUM_THREADS8intNUM_THREADS=1;chararray[N];void*countMs_thread(void*id);intcount;intmain(){clock_tstart,end;inti,rc,t;scanf(%d,&NUM_THREADS);pthread_tthread[NUM_THREADS];for(i=0;iN;i+=2){array[i]='M';array[i+1]='P';}start=clock();for(t=0;tNUM_THREADS;t++){printf(Creatingthread%d\n,t);rc=pthread_create(&thread[t],NULL,countMs_thread,(void*)t);if(rc){printf(ERROR;returncodeis%d\n,rc);return0;}}for(t=0;tNUM_THREADS;t++)pthread_join(thread[t],NULL);end=clock();printf(Thereis%dM\n,count);printf(Timeis%dms.,end-start);return0;}void*countMs_thread(void*id)//id为创建线程时传入的线程号{inti;/*computeportionofthearraythatthisthreadshouldworkon*/intlength_per_thread=N/NUM_THREADS;//每个线程分担的元素个数intstart=(int)id*length_per_thread;//本线程负责的数组下标起点for(i=start;istart+length_per_thread;i++)//遍历本线程负责的所有元素{if(array[i]=='M'){count++;//将总数增1}}}执行结果:核数124816时间(ms)6816583095707604489212693759242704510500000010000000150000002000000025000000124816时间结果分析:程序二采用简单的简单采用pthread并行执行.当核数等于1时,对M的统计结果正确,时间与程序串行执行的时间相当。当核数大于1时,计算结果不再正确,而且随着核数的增加执行时间增加。由于对全局变量count的访问不是互斥的,一个线程访问的同时可能另一个线程也来访问这个变量,导致结果错误。3)完整代码:#includestdio.h#includetime.h#includepthread.h#includeunistd.h#defineN1024*1024*256//#defineNUM_THREADS8intNUM_THREADS=1;chararray[N];void*countMs_thread(void*id);intcount;pthread_mutex_tm;intmain(){clock_tstart,end;start=clock();inti,rc,t;pthread_mutex_init(&m,NULL);scanf(%d,&NUM_THREADS);pthread_tthread[NUM_THREADS];for(i=0;iN;i+=2){array[i]='M';array[i+1]='P';}start=clock();for(t=0;tNUM_THREADS;t++){//printf(Creatingthread%d\n,t);rc=pthread_create(&thread[t],NULL,countMs_thread,(void*)t);if(rc){printf(ERROR;returncodeis%d\n,rc);return0;}}for(t=0;tNUM_THREADS;t++)pthread_join(thread[t],NULL);end=clock();pthread_mutex_destroy(&m);printf(Thereis%dM\n,count);printf(Timeis%dms.,end-start);return0;}void*countMs_thread(void*id)//id为创建线程时传入的线程号{inti;/*computeportionofthearraythatthisthreadshouldworkon*/intlength_per_thread=N/NUM_THREADS;//每个线程分担的元素个数intstart=(int)id*length_per_thread;//本线程负责的数组下标起点for(i=start;istart+length_per_thread;i++)//遍历本线程负责的所有元素{if(array[i]=='M'){pthread_mutex_lock(&m);count++;pthread_mutex_unlock(&m);//将总数增1}}}执行结果:核数124816时间3002031155129719184479675104041138726840020000000400000006000000080000000100000000120000000140000000124816时间结果分析:加上pthread的互斥锁mutext后,每次访问count时先申请mutext,访问结束后释放mutex,从而实现互斥访问,计算M的个数均为134217728,保证计算结果正确。但是同时可以看到虽然核数增多了,但是计算速度并没有加快,反而比串行

1 / 16
下载文档,编辑使用

©2015-2020 m.777doc.com 三七文档.

备案号:鲁ICP备2024069028号-1 客服联系 QQ:2149211541

×
保存成功