C++ MPI项目中MPI_Send发送char数组向量接收错误如何解决
MPI发送char数组向量异常的原因与修复方案
问题根因
- 核心逻辑错误:
vector<char*>存储的是内存指针,指针仅在当前进程的地址空间有效,跨进程发送指针本身毫无意义,接收进程拿到的是野指针,无法访问到对应字符串内容。 - MPI调用参数错误:
MPI_Send(&cstrings[0], cstrings.size(), MPI_CHAR,...)仅发送了2个字节的内容(对应两个char指针的前2个字节),完全没有发送字符串的实际存储内容。 - 临时对象悬空引用:构造
cstrings时,循环内的string st是局部临时变量,循环结束后立即销毁,存储的&st[0]属于悬空指针,即使在进程0本地后续访问也属于未定义行为,打印正常只是内存未被覆盖的巧合。
修复方案
这里采用序列化所有字符串到连续缓冲区的方案,实现简单且通信次数少,步骤如下:
- 进程0先统计所有字符串的总长度(包含每个字符串的
\0结束符),构造连续的char缓冲区,把所有字符串依次拷贝到缓冲区中 - 先发送总长度给接收进程,接收进程申请对应大小的缓冲区后接收完整的字符内容
- 接收进程再从缓冲区中拆分出各个字符串
修正后可运行代码
#include "mpi.h" #include <iostream> #include <string> #include <vector> #include <cstring> using namespace std; int main(int argc, char **argv) { int rank, numprocs; MPI_Init(NULL, NULL); MPI_Comm_rank(MPI_COMM_WORLD, &rank); MPI_Comm_size(MPI_COMM_WORLD, &numprocs); if (rank==0) { std::vector<std::string> strings = {"fe", "fo"}; // 计算总长度,每个字符串加1存'\0' int total_len = 0; for (auto& s : strings) { total_len += s.size() + 1; } // 构造连续缓冲区 std::vector<char> send_buf(total_len); int offset = 0; for (auto& s : strings) { strcpy(send_buf.data() + offset, s.c_str()); offset += s.size() + 1; } // 先发总长度,再发内容 MPI_Send(&total_len, 1, MPI_INT, 1, 0, MPI_COMM_WORLD); MPI_Send(send_buf.data(), total_len, MPI_CHAR, 1, 1, MPI_COMM_WORLD); } if (rank==1) { int total_len = 0; // 先收总长度,申请缓冲区 MPI_Recv(&total_len, 1, MPI_INT, 0, 0, MPI_COMM_WORLD, MPI_STATUS_IGNORE); std::vector<char> recv_buf(total_len); MPI_Recv(recv_buf.data(), total_len, MPI_CHAR, 0, 1, MPI_COMM_WORLD, MPI_STATUS_IGNORE); // 拆分字符串 std::vector<std::string> recv_strings; int offset = 0; while (offset < total_len) { std::string s(recv_buf.data() + offset); recv_strings.push_back(s); offset += s.size() + 1; } // 打印验证 for (auto& s : recv_strings) { cout << s << endl; } } MPI_Finalize(); return 0; }
内容的提问来源于stack exchange,提问作者Giulio Mattolin
相关产品推荐
相关产品推荐

