一下所有代码都是可以运行,执行成功的。
/************************************
// 程序功能: MPI_Gatherv函数的测试
// 作 成 者:Erick.Wang
// 作成日期:2016/12/13
// 程序说明:
************************************/
#include <mpi.h>
#include <stdio.h>
#include <stdlib.h>
#pragma comment(lib,"mpi.lib")
#pragma message("**** MPI_Gatherv *******")
/***********************************************************************
int MPI_Gatherv(void* sendbuf, int sendcount, MPI_Datatype sendtype,
void* recvbuf, int *recvcounts, int *displs,
MPI_Datatype recvtype, int root, MPI_Comm comm)
IN sendbuf 发送消息缓冲区的起始地址(可变)
IN sendcount 发送消息缓冲区中的数据个数(整型)
IN sendtype 发送消息缓冲区中的数据类型(句柄)
OUT recvbuf 接收消息缓冲区的起始地址(可变,仅对于根进程)
IN recvcounts 整型数组(长度为组的大小), 其值为从每个进程接收的数据个数(仅对于根进程)
IN displs 整数数组,每个入口i表示相对于recvbuf的位移,
此位移处存放着从进程i中接收的输入数据(仅对于根进程)
IN recvtype 接收消息缓冲区中数据类型(仅对于根进程)(句柄)
IN root 接收进程的序列号(句柄)
IN comm 通信子(句柄)
它可以从不同的进程接收不同数量的数据
***********************************************************************/
int main(int argc,char* argv[])
{
#if 1
int nprocs,rank;
MPI_Init(&argc,&argv);
MPI_Comm_rank(MPI_COMM_WORLD,&rank);
MPI_Comm_size(MPI_COMM_WORLD,&nprocs);
/***********************************************************************
每个进程向根进程发送100个整型数,但在接收端设置每个集合(100个数据)的步长,
用MPI_Gatherv函数和displs参数来实现,假设步长≥100
***********************************************************************/
const int n = 100;
int sendBuf[n],*recvBuf;
int *displs,stride,*recvCount; //stride:步长
//数据初始化
for (int i=0; i<n; i++){
sendBuf[i] = i;
}
//设置步长、偏移量、接收数据量
stride = n;
displs = (int *)malloc(sizeof(int)*nprocs); //一个进程一个偏移
recvCount = (int *)malloc(sizeof(int)*nprocs); //一个进程一个接收数据量
for (int i=0; i<nprocs; i++){
displs[i] = i*stride;
recvCount[i] = n;
}
//每个进程发送n个int,而每个数据块的步长为stride(stride≥n),则接收缓冲区大小为stride*nprocs
recvBuf = (int *)malloc(stride*nprocs*sizeof(int));
//执行接收操作
int root = 0;
MPI_Gatherv(sendBuf,n,MPI_INT,recvBuf,recvCount,displs,MPI_INT,root,MPI_COMM_WORLD);
//打印显示
if(rank == 0){
for (int i=0; i<nprocs; i++){
for (int j=0; j<recvCount[i]; j++){
printf("%d ",recvBuf[j]);
}
printf("\n");
}
}
MPI_Finalize();
#endif
#if 0
/***********************************************************************
发送的数据是每个100*150数组的第0列中的100个数据
***********************************************************************/
int rank,nprocs;
MPI_Init(&argc,&argv);
MPI_Comm_rank(MPI_COMM_WORLD,&rank);
MPI_Comm_size(MPI_COMM_WORLD,&nprocs);
//初始化数据
int sendArray[100][150];
for (int i=0; i<100; i++){
for (int j=0; j<150; j++){
sendArray[i][j] = i;
}
}
//构造新的数据类型,用于数据的发送
MPI_Datatype newType;
//MPI_TYPE_VECTOR(count,blocklength,stride,oldtype,newtype)
//将第一列分成100个只包含1个元素的数据块,数据块间隔为150,因为C语言的数组是按行优先存储的
MPI_Type_vector(100,1,150,MPI_INT,&newType); //为数组中的第一列数据生成相应的数据类型
MPI_Type_commit(&newType);
int *disple,*recvCount;
int stride;
disple = (int *)malloc(sizeof(int)*nprocs); //一个进程一个偏移量
recvCount = (int *)malloc(sizeof(int)*nprocs); //一个进程一个接收数据量
//设置步长、接收数据个数、数据块偏移量
stride = 100;
for (int i=0; i<nprocs; i++){
disple[i] = i * stride;
recvCount[i] = 100;
}
//设置接收缓冲区
int *recvBuf = (int *)malloc(sizeof(int)*stride*nprocs);
//执行接收操作
int root = 0;
MPI_Gatherv(sendArray,1,newType,recvBuf,recvCount,disple,MPI_INT,root,MPI_COMM_WORLD);
//打印显示
if(rank == 0){
for (int i=0; i<nprocs; i++){
for (int j=0; j<recvCount[i]; j++){
printf("%d ",recvBuf[j]);
}
printf("\n");
}
}
MPI_Finalize();
#endif
#if 0
int rank,nprocs;
MPI_Init(&argc,&argv);
MPI_Comm_rank(MPI_COMM_WORLD,&rank);
MPI_Comm_size(MPI_COMM_WORLD,&nprocs);
/***********************************************************************
进程i将100*150的整数数组中第i列的100-i个整数发送给根进程
***********************************************************************/
int sendArray[100][150];
//初始化
for (int i=0; i<100; i++){
for (int j=0; j<150; j++){
sendArray[i][j] = i+j;
}
}
//为要发送的数据构造新的数据类型
MPI_Datatype newType;
MPI_Type_vector(100-rank,1,150,MPI_INT,&newType);
MPI_Type_commit(&newType);
int *displs,*recvCount;
int stride;
//设置步长、接收数据量、数据块偏移量
stride = 100;
displs = (int *)malloc(sizeof(int)*nprocs);
recvCount = (int *)malloc(sizeof(int)*stride*nprocs);
for (int i=0; i<nprocs; i++){
displs[i] = i*stride;
recvCount[i] = 100-i;
}
//设置接收缓冲区
int *recvBuf = (int *)malloc(sizeof(int)*stride*nprocs);
//执行接收操作
int root = 0;
MPI_Gatherv(&sendArray[0][rank],1,newType,recvBuf,recvCount,displs,MPI_INT,root,MPI_COMM_WORLD);
//打印显示
if(rank == 0){
for (int i=0; i<nprocs; i++){
for (int j=0; j<recvCount[i]; j++){
printf("%d ",recvBuf[j]);
}
printf("\n");
}
}
MPI_Finalize();
#endif
#if 0
int rank,nprocs;
MPI_Init(&argc,&argv);
MPI_Comm_rank(MPI_COMM_WORLD,&rank);
MPI_Comm_size(MPI_COMM_WORLD,&nprocs);
/***********************************************************************
进程i从100*150数组的第i列开始发送num个整数.
这里比较困难的是根进程不知道变化的num的确切值,所以必须先收集各个num值,这些数据依次存放在接收端
***********************************************************************/
int sendArray[100][150];
//初始化
for (int i=0; i<100; i++){
for (int j=0; j<150; j++){
sendArray[i][j] = i+j;
}
}
int *recvCount;
int num = rank + 1;
//根进程首先收集num的数值
recvCount = (int *)malloc(sizeof(int)*nprocs);
MPI_Gather(&num,1,MPI_INT,recvCount,1,MPI_INT,0,MPI_COMM_WORLD);
int *displs;
//设置步长、接收数据量、数据块偏移量
displs = (int *)malloc(sizeof(int)*nprocs);
displs[0] = 0;
for (int i=1; i<nprocs; i++){
displs[i] = displs[i-1] + recvCount[i-1];
}
//设置接收缓冲区
int *recvBuf = (int *)malloc(sizeof(int)*(displs[nprocs-1]+recvCount[nprocs-1])*nprocs);
if (rank == 0){
for (int i=0; i<nprocs; i++){
printf("%d ",recvCount[i]);
}
printf("\n");
}
MPI_Datatype newType;
//构造新的数据类型用于数据发送
MPI_Type_vector(num,1,150,MPI_INT,&newType); //每列发送num个数据
MPI_Type_commit(&newType);
//执行接收操作
int root = 0;
MPI_Gatherv(&sendArray[0][rank],1,newType,recvBuf,recvCount,displs,MPI_INT,root,MPI_COMM_WORLD);
//打印显示
if(rank == 0){
for (int i=0; i<nprocs; i++){
for (int j=0; j<recvCount[i]; j++){
printf("%d ",recvBuf[j]);
}
printf("\n");
}
}
MPI_Finalize();
#endif
return 0;
}