使用MPI_Scatterv分发二维数组列时出现段错误问题
MPI_Scatterv分发二维数组列触发段错误的解决方法
问题场景
我有一个尺寸为N×M(N=13,M=17)的二维数组,使用8个进程按列分发数据:进程0获取3列,其余进程各获取2列(每列包含13个整数)。代码逻辑看似正确,但调用MPI_Scatterv函数时触发了段错误。
原代码
#include <mpi.h> #include <stdio.h> #include <stdlib.h> #include <math.h> #define N 13 #define M 17 int main(int argc, char *argv[]){ int matrix[N*M]; int menum, nproc, i, j; MPI_Init(&argc, &argv); MPI_Comm_rank(MPI_COMM_WORLD, &menum); MPI_Comm_size(MPI_COMM_WORLD, &nproc); //Matrix initialization if (menum == 0) { for (i = 0; i < N; i++) { for (j = 0; j < M; j++) { matrix[(i*M)+j] = i * M + j; } } } //Every process has its vector of size nloc*mloc int nloc = N; int mloc = menum < M%nproc ? (M/nproc)+1 : M/nproc; int *recv_vec = (int *)malloc(nloc*mloc*sizeof(int)); //Create a custom datatype for a vector of nloc integers MPI_Datatype col_type; MPI_Type_vector(nloc, 1, M, MPI_INT, &col_type); MPI_Type_commit(&col_type); //Distributing data to other processes int sendcounts[]={3,2,2,2,2,2,2,2}; int displs[]={0,3,5,7,9,11,13,15}; MPI_Scatterv(matrix, sendcounts, displs, col_type, recv_vec, nloc*mloc, MPI_INT, 0, MPI_COMM_WORLD); //Freeing up memory and terminate MPI environment free(recv_vec); MPI_Type_free(&col_type); MPI_Finalize(); return 0; }
问题原因
MPI_Type_vector创建的col_type虽然能正确描述数组中的一列,但它的**extent(类型跨度)**是基于原数组的行宽M计算的(即M*sizeof(int))。当MPI_Scatterv使用这个类型计算后续列的偏移时,会错误地按原数组行宽跳转,导致访问超出数组范围,触发段错误。
解决方案
使用MPI_Type_create_resized()调整自定义类型的extent,让它匹配单个整数的字节数(sizeof(int)),这样MPI_Scatterv就能正确计算每个进程数据的起始偏移位置。
修改后的代码
#include <mpi.h> #include <stdio.h> #include <stdlib.h> #include <math.h> #define N 13 #define M 17 int main(int argc, char *argv[]){ int matrix[N*M]; int menum, nproc, i, j; MPI_Init(&argc, &argv); MPI_Comm_rank(MPI_COMM_WORLD, &menum); MPI_Comm_size(MPI_COMM_WORLD, &nproc); //Matrix initialization if (menum == 0) { for (i = 0; i < N; i++) { for (j = 0; j < M; j++) { matrix[(i*M)+j] = i * M + j; } } } //Every process has its vector of size nloc*mloc int nloc = N; int mloc = menum < M%nproc ? (M/nproc)+1 : M/nproc; int *recv_vec = (int *)malloc(nloc*mloc*sizeof(int)); //Create a custom datatype for a vector of nloc integers MPI_Datatype col_type, resized_col_type; MPI_Type_vector(nloc, 1, M, MPI_INT, &col_type); // 调整类型的extent,使其按单个整数的大小计算偏移 MPI_Type_create_resized(col_type, 0, sizeof(int), &resized_col_type); MPI_Type_commit(&resized_col_type); //Distributing data to other processes int sendcounts[]={3,2,2,2,2,2,2,2}; int displs[]={0,3,5,7,9,11,13,15}; // 使用调整后的类型resized_col_type MPI_Scatterv(matrix, sendcounts, displs, resized_col_type, recv_vec, nloc*mloc, MPI_INT, 0, MPI_COMM_WORLD); //Freeing up memory and terminate MPI environment free(recv_vec); MPI_Type_free(&col_type); MPI_Type_free(&resized_col_type); MPI_Finalize(); return 0; }
修改要点
- 新增
resized_col_type,通过MPI_Type_create_resized()将原类型的跨度调整为单个整数的大小,确保列偏移计算正确。 MPI_Scatterv中替换为调整后的类型作为发送数据类型。- 新增对调整后类型的资源释放操作。
内容的提问来源于stack exchange,提问作者Amato.g
相关产品推荐
相关产品推荐

