MPI_Gatherv测试代码报错:vector subscript out of range问题咨询
嘿,作为MPI新手碰到这种坑太正常了,我来帮你拆解下问题出在哪,以及怎么排查修复!
先理清你问题的核心矛盾
你想用MPI_Gather+MPI_Gatherv收集动态大小的vector,但出现两个异常:
- 本该输出3的第一个cout,实际打出
0 0 3——说明根进程没正确收集到其他进程的vector大小 - 输出
2 1 5后崩溃,提示vector subscript out of range——这是根进程的目标vector容量不足,或者位移(displs)计算错误导致写入越界
一步步排查问题
1. 先检查MPI_Gather收集数据大小的环节
你第一个cout的异常,本质是根进程收集到的各进程size数组不对,大概率是下面某一个问题:
- 是不是只有进程2的vector有数据,进程0、1的vector是空的?如果是,那你得先确认这两个进程的动态vector为什么没生成数据
- 检查
MPI_Gather的参数:收集size的时候,每个进程只需要发送1个int(就是本地vector的size),所以sendcount必须是1!如果你误把sendcount写成了local_size,那进程0/1的local_size是0,就会发送0个数据,根进程收到的就是脏值(比如0) - 根进程的接收数组(比如
recv_sizes)有没有提前resize到进程总数?如果没resize,数组是空的,写入的时候会触发内存越界,导致收集到随机值(比如0)
2. 再排查根进程的位移计算和目标vector分配
崩溃的直接原因是写入目标vector时超出了它的容量,你要检查这两点:
- 根进程收集到所有size后,有没有计算总大小并给目标vector扩容?比如必须执行
global_vec.resize(total_size),其中total_size是所有进程size的总和。如果没做这一步,目标vector默认大小是0,写入任何位置都会触发下标越界 - 位移数组(displs)的计算是否正确?正确的逻辑是:
要是你误把displs[0] = 0; for(int i=1; i<进程数; i++){ displs[i] = displs[i-1] + recv_sizes[i-1]; }recv_sizes[i-1]写成了recv_sizes[i],位移就会乱掉,导致写入位置超出vector容量
3. 最后检查MPI_Gatherv的参数匹配
- 确认
sendcount是每个进程的本地vector大小(local_size),recvcounts是收集到的recv_sizes数组,displs是刚才计算的位移数组 - MPI数据类型要和vector的元素类型匹配:比如vector存的是int,就用
MPI_INT,不能错用MPI_FLOAT之类的,否则会导致数据乱码或内存错误
给你一个正确的参考示例片段
#include <mpi.h> #include <vector> #include <iostream> int main(int argc, char** argv) { MPI_Init(&argc, &argv); int rank, proc_num; MPI_Comm_rank(MPI_COMM_WORLD, &rank); MPI_Comm_size(MPI_COMM_WORLD, &proc_num); // 每个进程生成动态大小的vector std::vector<int> local_vec; if (rank == 0) local_vec = {1,2}; // size=2 else if (rank ==1) local_vec = {3}; // size=1 else if (rank ==2) local_vec = {4,5,6,7,8}; // size=5 int local_size = local_vec.size(); std::vector<int> recv_sizes; std::vector<int> displs; std::vector<int> global_vec; // Step1: 收集所有进程的vector大小到根进程(rank=0) if (rank == 0) { recv_sizes.resize(proc_num); } MPI_Gather(&local_size, 1, MPI_INT, recv_sizes.data(), 1, MPI_INT, 0, MPI_COMM_WORLD); // 根进程计算总大小和位移 if (rank == 0) { int total_size = 0; displs.resize(proc_num); displs[0] = 0; for(int i=0; i<proc_num; i++){ total_size += recv_sizes[i]; if(i > 0) displs[i] = displs[i-1] + recv_sizes[i-1]; } global_vec.resize(total_size); // 这里输出的应该是2 1 5 std::cout << "Received sizes: "; for(int s : recv_sizes) std::cout << s << " "; std::cout << std::endl; } // Step2: 用Gatherv收集实际数据 MPI_Gatherv(local_vec.data(), local_size, MPI_INT, global_vec.data(), recv_sizes.data(), displs.data(), MPI_INT, 0, MPI_COMM_WORLD); // 根进程输出最终结果 if(rank == 0){ std::cout << "Global vector: "; for(int num : global_vec) std::cout << num << " "; std::cout << std::endl; } MPI_Finalize(); return 0; }
内容的提问来源于stack exchange,提问作者thestudentIT
相关产品推荐
相关产品推荐

