MPI点对点通信求进程最大值:多进程重复打印问题排查
MPI环形结构求最大值异常:多进程重复打印结果问题排查
问题描述
尝试通过MPI点对点通信,在环形拓扑的进程组中找出最大值(后续将扩展最小值功能)。0号进程向右侧1号进程发起数据传递,预期仅持有最大值的进程打印结果,但部分场景下会出现多个进程同时输出结果的情况。
问题代码
#include <stdio.h> #include <stdlib.h> #include<unistd.h> #include <mpi.h> int main(int argc, char **argv) { int rank, size, tag = 100; int rightrank, leftrank; int v, min, max, i, tmpmax, tmpmin; int *data; MPI_Init(&argc, &argv); MPI_Comm_rank(MPI_COMM_WORLD, &rank); MPI_Comm_size(MPI_COMM_WORLD, &size); MPI_Status status; data = (int*) malloc(size * sizeof(int)); rightrank = rank + 1; leftrank = rank - 1; if (rank == 0) { leftrank = size - 1; } if (rank == size - 1) { rightrank = 0; } for (i = 0; i < size; i++) { data[i] = rand() % 60; } v = data[rank]; //v=rank*10; printf("{rank %d , v = %d }\n", rank, v); if (rank == 0) { MPI_Send(&v, 1, MPI_INT, rightrank, tag, MPI_COMM_WORLD); MPI_Recv(&tmpmax, 1, MPI_INT, leftrank, tag, MPI_COMM_WORLD, &status); } else { MPI_Recv(&tmpmax, 1, MPI_INT, leftrank, tag, MPI_COMM_WORLD, &status); max = tmpmax; if (v > max) { max = v; } MPI_Send(&max, 1, MPI_INT, rightrank, tag, MPI_COMM_WORLD); } if (v == max) { printf("Me process of rank %d i have max value v = %d\n ", rank, v); } MPI_Finalize(); return 0; }
问题原因分析
0号进程
max变量未初始化:
非0号进程在接收数据后会初始化max并更新,但0号进程仅发送自身值、接收最终全局最大值到tmpmax,却从未将tmpmax赋值给max。此时0号进程的max是未定义的垃圾值,若该值恰好等于自身v,就会错误触发打印逻辑。全局随机数种子一致导致重复值:
所有进程调用rand()前未设置独立随机种子,默认种子相同,导致每个进程生成的data数组完全一致,多个进程的v值相同。这些进程的v都会等于传递后的全局最大值,从而同时打印结果。
修复方案
1. 补全0号进程的max变量初始化
在0号进程接收完tmpmax后,将其赋值给max,确保0号进程持有正确的全局最大值:
if (rank == 0) { MPI_Send(&v, 1, MPI_INT, rightrank, tag, MPI_COMM_WORLD); MPI_Recv(&tmpmax, 1, MPI_INT, leftrank, tag, MPI_COMM_WORLD, &status); max = tmpmax; // 新增:将接收的全局最大值赋值给max }
2. 为每个进程设置独立随机数种子
在生成随机数前,用rank区分种子,避免所有进程生成相同的随机数据:
// 在data数组生成前添加 srand(time(NULL) + rank);
修复后的完整代码
#include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <time.h> #include <mpi.h> int main(int argc, char **argv) { int rank, size, tag = 100; int rightrank, leftrank; int v, max, i, tmpmax; int *data; MPI_Init(&argc, &argv); MPI_Comm_rank(MPI_COMM_WORLD, &rank); MPI_Comm_size(MPI_COMM_WORLD, &size); MPI_Status status; data = (int*) malloc(size * sizeof(int)); rightrank = rank + 1; leftrank = rank - 1; if (rank == 0) { leftrank = size - 1; } if (rank == size - 1) { rightrank = 0; } // 设置独立随机种子 srand(time(NULL) + rank); for (i = 0; i < size; i++) { data[i] = rand() % 60; } v = data[rank]; printf("{rank %d , v = %d }\n", rank, v); if (rank == 0) { MPI_Send(&v, 1, MPI_INT, rightrank, tag, MPI_COMM_WORLD); MPI_Recv(&tmpmax, 1, MPI_INT, leftrank, tag, MPI_COMM_WORLD, &status); max = tmpmax; // 初始化0号进程的max } else { MPI_Recv(&tmpmax, 1, MPI_INT, leftrank, tag, MPI_COMM_WORLD, &status); max = tmpmax; if (v > max) { max = v; } MPI_Send(&max, 1, MPI_INT, rightrank, tag, MPI_COMM_WORLD); } if (v == max) { printf("进程%d持有最大值:%d\n", rank, v); } free(data); // 释放内存 MPI_Finalize(); return 0; }
效果说明
修复后,全局最大值会正确在环形中传递并更新,每个进程都持有正确的全局最大值,仅真正拥有最大值的进程会打印结果;同时每个进程生成的随机值独立,避免因重复值导致的误打印。
内容的提问来源于stack exchange,提问作者MRS
相关产品推荐
相关产品推荐

