C++使用MPI如何收集各进程char字符串并逐进程打印输出
问题原因
你代码的核心错误有4处:
- 接收缓冲区溢出:你定义的
receive数组初始化为"nothing",长度只有8字节(含末尾\0),但要接收的"received"长度是9字节,写入时越界破坏了内存数据。 - 打印逻辑错误:
totalstring是按位移存储所有进程的完整字符串,你直接用totalstring[i]只会取到第i个字节的单个字符,自然是逐字符输出。 - 数组分配错误:
new int[nbproc*sizeof(int)]写法错误,new运算符后面跟的是元素个数,不是字节数,多分配了几倍空间属于无用操作。 - 数组越界写入:你给
totalstring分配了totlen大小的空间,却执行totalstring[totlen] = '\0',下标从0开始的情况下totlen属于越界位置。
修正后的代码
#include <iostream> #include <cstring> #include <mpi.h> using namespace std; int main(int argc, char** argv) { int rank, nbproc, taille; char name[80]; char message[] = "preceived"; int longueur = strlen(message); const int len_buffer = 200; char Buffer_Hello[len_buffer]; // 修正1:把receive数组改大,避免接收溢出 char receive[20] = "nothing"; MPI_Init(&argc, &argv); MPI_Comm_size(MPI_COMM_WORLD, &nbproc); MPI_Comm_rank(MPI_COMM_WORLD, &rank); MPI_Get_processor_name(name, &taille); sprintf(Buffer_Hello, "Hello from process %d among %d of the machine %s", rank, nbproc, name); // 调整发送时机,避免不必要的缓冲占用 if (rank != 0) { MPI_Send(Buffer_Hello, len_buffer, MPI_CHAR, 0, rank+10, MPI_COMM_WORLD); } if (rank == 4) { MPI_Send(&message[1], longueur, MPI_CHAR, 5, 2, MPI_COMM_WORLD); } if (rank == 5) { MPI_Recv(receive, 20, MPI_CHAR, 4, 2, MPI_COMM_WORLD, MPI_STATUS_IGNORE); } int mylen = strlen(receive); // 修正2:数组分配不需要乘sizeof(int) int* recvcounts = new int[nbproc]; MPI_Gather(&mylen, 1, MPI_INT, recvcounts, 1, MPI_INT, 0, MPI_COMM_WORLD); int totlen = 0; int* displs = new int[nbproc]; if(rank == 0) { displs[0] = 0; totlen += recvcounts[0] + 1; for(int i=1; i < nbproc; i++) { totlen += recvcounts[i]+1; displs[i] = displs[i-1] + recvcounts[i-1] + 1; } } char* totalstring = new char[totlen]; if(rank == 0) { for (int i=0; i<totlen; i++) totalstring[i] = '\0'; } MPI_Gatherv(receive, mylen, MPI_CHAR, totalstring, recvcounts, displs, MPI_CHAR, 0, MPI_COMM_WORLD); if(rank == 0) { // 先打印进程0的信息 cout << Buffer_Hello << endl; cout << totalstring + displs[0] << endl; // 修正3:从displs[i]位置开始打印对应进程的完整字符串 for(int i = 1; i < nbproc; i++) { MPI_Recv(Buffer_Hello, len_buffer, MPI_CHAR, i, i+10, MPI_COMM_WORLD, MPI_STATUS_IGNORE); cout << Buffer_Hello << endl; cout << totalstring + displs[i] << endl; } } delete[] recvcounts; delete[] displs; delete[] totalstring; MPI_Finalize(); return 0; }
修改说明
- 把
receive数组扩容到20字节,完全容纳可能的字符串,避免接收溢出 - 修正数组分配逻辑,new时只传元素个数即可
- 打印时用
totalstring + displs[i]获取对应进程的字符串首地址,输出完整字符串 - 初始化
totalstring时直接填充\0,避免后续字符串输出异常 - 补充了内存释放逻辑,避免内存泄漏
- 调整了非0进程发送
Buffer_Hello的逻辑,只在非0进程执行发送,避免进程0做无用发送
内容的提问来源于stack exchange,提问作者Jejouze
相关产品推荐
相关产品推荐

