燕山大学多核程序设计实验报告.docx
《燕山大学多核程序设计实验报告.docx》由会员分享,可在线阅读,更多相关《燕山大学多核程序设计实验报告.docx(26页珍藏版)》请在冰豆网上搜索。
燕山大学多核程序设计实验报告
实验一Windows多线程编程
一、实验目的与要求
了解windows多线程编程机制
掌握线程同步的方法
二、实验环境和软件
WindowsXP
VC6.0
三、实验内容
创建线程:
HANDLECreateThread(
LPSECURITY_ATTRIBUTESlpThreadAttributes,
SIZE_TdwStackSize,
LPTHREAD_START_ROUTINElpStartAddress,
LPVOIDlpParameter,
DWORDdwCreationFlags,
LPDWORDlpThreadId
);
四、实验程序
#include"stdafx.h"
#include
#include
#include
#include
usingnamespacestd;
voidThreadFrunc1(PVOIDparam)
{
while
(1)
{
Sleep(1000);
cout<<"ThisisThreadFrunc1"<}
}
voidThreadFrunc2(PVOIDparam)
{
while
(1)
{
Sleep(1000);
cout<<"ThisiskjjThreadFrunc2"<}
}
intmain()
{
inti=0;
_beginthread(ThreadFrunc1,0,NULL);
_beginthread(ThreadFrunc2,0,NULL);
Sleep(3000);
cout<<"end"<return0;
}
实验结果
实验二蒙特卡罗法求PI
1、实验目的和要求
蒙特卡洛算法可理解为通过大量实验,模拟实际行为,来收集统计数据。
本例中,算法随机产生一系列点,模拟这些点落在如下图所示的正方形区域内的情况。
其几何解释如下
图1
如图1所示,正方形边长为1,左下顶点与原点重合,两边分别与x,y轴重合。
曲线为1/4圆弧,圆心位于原点,与正方形左下定点重合,半径为1。
正方形面积S1=1,圆弧内面积S2=
。
算法模拟大量点随机落在此正方形区域内,落在圆弧内的点的数量(n2)与点的总数(n1)的比例与面积成正比关系。
即
(1)
由此可得
(2)
因此,只要计算出落在圆弧内的点的数量在点总数中所占的比例,就能求出
的值。
由图1可知,所有点均落在正方形范围内,因此点的x坐标满足
。
又,当点落在圆弧范围内,则点的二维坐标关系满足
。
检验每一个点是否满足此关系即可判定改点是否落在圆弧内。
2、实验环境和软件
编译器:
MicrosoftVisualStudioC++6.0
操作系统:
WindowsXP
三、实验内容
3.1串行算法
本项目中使用了标准C语言库中的产生随机数函数。
该函数原型为:
intrand(void);
此函数产生随机数列,每次调用时均返回0到RAND_MAX之间的一个整数。
voidsrand(unsignedintseed);
此函数为rand()函数所生成的伪随机数序列设置起始点,使之产生不同的伪随机数。
算法:
产生2n个随机数据,范围[0,1],对每个数据点计算其坐标是否满足
,统计满足此关系的点的数量count,则
3.2并行算法描述
算法步骤:
1、确定需要产生的点的个数n,参与运行的处理器数m;
2、对每一个处理器,生成两个随机数x,y,范围[0,1];
3、判断两个随机数x,y是否满足
;
4、若满足,则变量COUNTi++;
5、重复步骤2-4,直至每个处理器均生成n/m个随机点;
6、收集COUNTi的值,并累加至变量COUNT中,此即为随机点落在圆弧内的数量;
7、通过
(2)式计算
的值。
3.3并行算法在Windows下的一个例子
#include
#include
#include
//#include
#include
#include
#include
usingnamespacestd;
HANDLEevFinish;
longcs=0;//总循环次数
longcount=0;//主线程有效次数
longcount_thread=0;//thread线程有效次数
time_tstart,finish;//定义开始结束时间
//thread线程计算量为总数的一半
DWORDWINAPIthread(LPVOIDparam)
{inti=0;
doublex,y;
for(i=0;i{
x=(longdouble)rand()/(longdouble)RAND_MAX;
y=(longdouble)rand()/(longdouble)RAND_MAX;
if((x*x+y*y)<=1)
count_thread++;
//printf("副%d",i);
}
SetEvent(evFinish);
return0;
}
//主线程计算量为总数的一半
intmain(void)
{
evFinish=CreateEvent(NULL,FALSE,FALSE,NULL);
printf("请输入总循环次数:
");
scanf("%d",&cs);
cs*=1000000;
srand((unsigned)time(NULL));//用时间作随机数种子
start=time(NULL);//记录开始时间
HANDLEid=CreateThread(NULL,0,thread,NULL,0,NULL);//创建thread线程
inti=0;
doublex,y;
for(i=0;i{
x=(longdouble)rand()/(longdouble)RAND_MAX;
y=(longdouble)rand()/(longdouble)RAND_MAX;
if((x*x+y*y)<=1)
count++;
//printf("主%d",i);
//printf("count%d",count);
}
WaitForSingleObject(evFinish,INFINITE);//两线程同步
count+=count_thread;
finish=time(NULL);//记录结束时间
printf("并行情况:
\n\n");
printf("用时=%f秒\n",difftime(finish,start));//计算时间差printf("总共的循环次数=%d次\n",cs);
printf("线程有效次数=%d次\n",count);
printf("pi=%f\n",4*(double)count/(double)cs);
printf("串行行情况:
\n");
count=0;
start=time(NULL);//记录开始时间
for(i=0;i{
x=(longdouble)rand()/(longdouble)RAND_MAX;
y=(longdouble)rand()/(longdouble)RAND_MAX;
if((x*x+y*y)<=1)
count++;
//printf("主%d",i);
//printf("count%d",count);
}
finish=time(NULL);//记录结束时间
printf("用时=%f秒\n",difftime(finish,start));
printf("总共的循环次数=%d次\n",cs);
printf("线程有效次数=%d次\n",count);
printf("pi=%f\n",4*(double)count/(double)cs);
return(0);
}
实验结果:
测试数据集合:
由随机数函数产生的数据集合
实验三并行排序
1、实验目的与要求
在单核计算环境中,排序算法关注的核心问题是怎样减少要排序数据之间的比较次数或算法所需要的内存空间。
在多核计算环境中,每个核以线程为执行单元,排序程序可以通过生成相互协作的线程来完成排序。
与单核计算环境不同的是,在多核计算环境中更关注数据集的合理划分,更致力于识别可并行执行的任务。
一旦完成这些工作,程序设计上就可以生成对应的线程去执行任务。
理论上,基于相同的串行算法和相同的cache命中率,多核计算速度可以无限接近单核计算速度的P倍,其中P为核的数目。
多核上的并行排序算法所面临的问题在于:
1.未排序的数据集合理划分到每个线程后,最后怎么汇合,形成完整的排好序的数据集呢?
2.怎么保证可并行执行的线程的数目和核的数目相等或稍微多于核的数目,同时也保证这些线程之间的工作量也尽可能的相同呢?
在这个实验中,串行的算法采用标准C语言库中的快速排序函数。
并行算法中,先将要处理的数据集均等的分到每个线程中,并使用C语言库中的快速排序函数各自排序。
然后所有线程开始根据相同的数对自己的数据集进行划分,这个数是依据一定的方法选出来的(详见并行算法描述)。
每个线程的数据集都会被分成K份,(其中P<=K很显然这个过程选出了K个数,这些数将被成为bound_value,记为X1,X2,X3……XK。
最后每个线程中小于或等于X1的数会被一个独立的线程去归并排序,同样小于或等于X2的数也会被另外一个独立的线程去归并排序,依次类推,直到排好序。
需要指出的是:
这个并行版本最消耗时间的部分是一开始每个线程各自的排序,时间为:
O(
);不过其数据划分和线程生成也相对简单。
最后的归并排序所需时间是线性增长的,即:
O(
),因此即使在最后归并部分线程执行的任务已经是不均衡的,也不会对整个程序的性能产生很大的影响。
2、实验环境和软件
编译器:
MicrosoftVisualStudioC++6.0
操作系统:
WindowsXP
3、实验内容
3.1并行算法描述
算法:
将原始待排序的数据分成P等份,每个处理器上对N0个数据进行排序,称每个被排序后的子集为B0,…,Bp-1
Remain_data=N,设定第0组归并起始位置全部为0,i=0,设置第0组在目标数组中的起始位置为0
循环直至remian_data3.1选取所有子集中起始位置后续L个元素的最小值bound_value,并获得bound_value的桶号bucket
3.2在所有子集中从起始位置到后续L个元素中选取边界位置,使得边界位置的最后一个元素小于或等于bound_value,而边界位置后的第一元素大于bound_value。
3.3记录所有的边界位置,并设置所有第i+1组的起始位置为第i组的起始位置加上边界位置
3.4累积所有边界值,得到该归并组的大小
3.5根据归并组大小和本组起始位置计算第i+1组在目标数组中的起始位置。
4、设置最后一个归并组的边界为N0
5、对所有归并组进行并行P路归并排序。
4、实验步骤
说明:
A.P和多核处理器的数目相同。
比如是双核的,那么P=2;
B.Remain_data是每个线程处理的数据集中还没有被X1,X2,X3……划分过的数据集的总数目。
比如,根
据X1每个线程划分出来的数据集为x,y,z……,那么Remain_data=n–x–y–z…..
并行算法在Windows下的一个例子
#include
#include
#include
#include
#include
#include
#ifndef_BASIC_SORT_H
#define_BASIC_SORT_H
#ifndef_SORT_P
#define_SORT_P
void*sort(void*parameter);
voidgenerate_data(int*a,intn);
voidsort_s(int*a,intn);
voidview_data(int*a,intn);
intcheck_data_sort(int*a,intn);
intcompare(constvoid*arg1,constvoid*arg2);
#defineMILLION1000000L
#defineP2
#defineN04332539
//#defineN01000000
#defineNN0*P
#defineLN0/P
voidsort_p(int**d,int*b);
time_tstart,finish;//定义开始结束时间
structmerge{//归并结构
intbegin[P];//数组begin
intcount[P];//数组count
intmerge_size;//归并大小
intglobal_pos;//全局位置
intmerged;//归并是否完成
};
structarg_merge_data{//归并数据结构
int**d;//数组的指针
structmerge*mp;//归并结构
int*b;//整数b
intk;
};
structarg_merge_data*tmp2;
structforsort{
int*d;
intk;
};
structforsortforsorta[P];
intfind_bound_value(int**d,structmerge*mp,int*bucket);
intfind_min(int**d,structmerge*mp,int*bucket);
voidfind_bound(int**d,structmerge*mp,intbucket,intbound_value);
voiddo_last_merge_block(structmerge*mp);
voidmerge_data(void*arg);
voidview_merge(int**d,structmerge*mp,intlast_merge_block);
intstart_time();
intdiff_time();
#endif
#endif
intk;
HANDLESwait[P];
HANDLEPwait[P];
HANDLEpthread[P];
HANDLEqthread[P];
externint*d[P];
///////////////////////////////////////////////////////////////////
voidgenerate_data(int*a,intn){//产生数据
inti;
for(i=0;ia[i]=rand()%10000;//产生数组a有n个元素
}
for(i=0;i
d[i]=&(a[i*N0]);//产生数组d对应a[i]中每个n0块的第i个元素
}
}
////////////////////////////////////////////////////////////////////
voidsort_s(int*a,intn){//快排a[i]
qsort((void*)a,n,sizeof(int),compare);
}
////////////////////////////////////////////////////////////////////
void*sort(void*parameter){//快排参数(数组)的前N0个元素
structforsort*forsortb=(structforsort*)parameter;
//printf("\nSetEvent(Swait[%d])",forsortb->k);/////////////////=====================
intkk=forsortb->k;
qsort(/*(void*)*/forsortb->d,N0,sizeof(int),compare);
SetEvent(Swait[kk]);//printf("\n%d",kk);
return(void*)0;
}
///////////////////////////////////////////////////////////////////
voidview_data(int*a,intn){
inti=n,j;
intindex=0;
while(i>N0){
for(j=0;jprintf("%d\t",a[index++]);//输出a[i]中前N0个数
}
printf("\n");
i-=N0;
}
for(;i>0;i--){//输出a[i]中N0后面的个数
printf("%d\t",a[index++]);
}
printf("\n");
}
//////////////////////////////////////////////////////////////////////
intcheck_data_sort(int*a,intn){//找出不服和大小顺序的位置
inti;
for(i=0;iif(a[i]>a[i+1])break;
}
returni;
}
//////////////////////////////////////////////////////////////////////
intcompare(constvoid*arg1,constvoid*arg2){//返回arg1与arg2的差
inta=*(int*)arg1,b=*(int*)arg2;
returna-b;
}
////////////////////////////////////////////////////////////////////
inta[N];//dataforparallelsort
intb[N];//theresultofparallelsort
int*d[P];//forparallelsort
ints[N];//dataforserialsort
structmergem_list[P*P];//recordofpartition
intmerge_block;//thenumberofpartition
DWORDthr_id[P*P];
longtimedif;//forestimatetheexectiontime
//structtimevalend;//...
//structtimevalstart;//...
voidinite()
{inti;
//forsorta=(structforsort*)calloc(P,sizeof(structforsort));
for(i=0;i
{
Swait[i]=CreateEvent(NULL,FALSE,FALSE,NULL);
Pwait[i]=CreateEvent(NULL,FALSE,FALSE,NULL);
/*for(intj=0;j
{
forsorta[i].d[j]=d[j];
//printf("forsorta[%d].d[%d]=%d\n",i,j,forsorta[i].d[j]);
}*/
}
}
voidmain(){
intdata;
inti;
generate_data(a,N);//产生数组a[n]
for(i=0;is[i]=a[i];
inite();
printf("请稍等....\n");
//start_time();
sort_p(d,b);
//diff_time();
start_time();
sort_s(s,N);
printf("单线程快排所用时间\n");
diff_time();
if((data=check_data_sort(b,N))==N-1)printf("SortisOK\n");
else{
printf("b[%d]>b[%d]\n",data,data+1);
}
}
//////////////////////////////////////////////////////////////////////////
intstart_time(){//记录开始时间函数
start=time(NULL);//记录开始时间
return0;
}
/////////////////////////////////////////////////////////////////////////
intdiff_time(){//记录结束时间并算时间差函数
finish=time(NULL);//记录结束时间
printf("用时=%f秒\n",difftime(finish,start));//输出结果
return0;
}
///////////////////////////////////////////////////////////////////////////
voidsort_p(int**d,int*b){
//tmp2=(arg_merge_data*)calloc(merge_block+l,sizeof(structarg_merge_data));
inti;
intremain_data=N;//剩余数据初始化
merge_block=0;//归并块=0