求可被多MPI进程调用但仅单次printf输出的C函数实现
单实例打印的MPI函数实现
针对需求,提供两种可行方案:
方案一:基于子通信子的集体调用版
该方案要求所有MPI进程调用函数,通过参数指定是否参与打印逻辑。参与进程会组成专属子通信子,由子通信子的rank 0进程执行打印,完全符合MPI规范,无死锁风险。
#include <mpi.h> #include <stdio.h> void mpi_collective_print_once(int is_participant, const char *msg) { MPI_Comm sub_comm; // 参与进程标记为颜色1,非参与进程标记为MPI_UNDEFINED(不加入子通信子) int color = is_participant ? 1 : MPI_UNDEFINED; int sub_rank; // 创建仅包含参与进程的子通信子 MPI_Comm_split(MPI_COMM_WORLD, color, 0, &sub_comm); if (is_participant) { MPI_Comm_rank(sub_comm, &sub_rank); // 子通信子的rank 0进程执行打印 if (sub_rank == 0) { printf("%s\n", msg); } // 销毁子通信子释放资源 MPI_Comm_free(&sub_comm); } }
使用示例:
- 若进程0、1、2需要调用,这三个进程传入
is_participant=1,其余进程传入0 - 若进程1、4需要调用,这两个进程传入
is_participant=1,其余传入0
方案二:基于原子操作的非集体调用版
该方案允许仅部分进程调用函数,无需未调用进程参与任何操作。通过共享内存的原子操作确保每次调用仅第一个进入函数的进程打印消息,支持多次不同进程集合的调用。
#include <mpi.h> #include <stdio.h> void mpi_print_once(const char *msg) { MPI_Win win; int *print_flag; int rank, result; const int one = 1; MPI_Comm_rank(MPI_COMM_WORLD, &rank); // 创建共享内存窗口,仅rank 0分配内存并初始化标志为0 if (rank == 0) { MPI_Alloc_mem(sizeof(int), MPI_INFO_NULL, &print_flag); *print_flag = 0; } else { print_flag = NULL; } MPI_Win_create(print_flag, sizeof(int), sizeof(int), MPI_INFO_NULL, MPI_COMM_WORLD, &win); // 原子操作:获取当前标志值并将其设为1 MPI_Win_lock(MPI_LOCK_EXCLUSIVE, 0, 0, win); if (rank == 0) { result = *print_flag; *print_flag = 1; } else { MPI_Fetch_and_op(&one, &result, MPI_INT, 0, 0, MPI_REPLACE, win); } MPI_Win_unlock(0, win); // 仅第一个获取到0值的进程打印消息 if (result == 0) { printf("%s\n", msg); } // 重置标志并销毁窗口,释放资源 MPI_Win_lock(MPI_LOCK_EXCLUSIVE, 0, 0, win); if (rank == 0) { *print_flag = 0; MPI_Free_mem(print_flag); } MPI_Win_unlock(0, win); MPI_Win_free(&win); }
说明:
- 每次调用函数都会创建新的共享内存窗口,调用完成后自动销毁,避免资源泄漏
- 原子操作确保打印逻辑的原子性,不会出现多次打印的情况
- 无需未调用函数的进程配合,完全符合“仅部分进程调用”的需求
内容的提问来源于stack exchange,提问作者apadana
相关产品推荐
相关产品推荐

