url: https://hpc-tutorials.llnl.gov/mpi/exercise_2/
Exercise 2
如下图是练习2的要求:

阻塞型
阻塞型代码:
#include "mpi.h" // MPI头文件
#include <stdio.h> // 标准输入输出头文件
#include <stdlib.h> // 标准库头文件
#define MASTER 0 // 定义主进程的rank为0
int main (int argc, char *argv[])
{
// MPI相关变量声明
int numtasks, // MPI任务总数(进程数)
taskid, // 当前任务的排名(进程ID)
len, // 处理器名称长度
partner, // 通信伙伴的进程排名
message; // 接收到的消息内容
char hostname[MPI_MAX_PROCESSOR_NAME]; // 存储处理器名称的数组
MPI_Status status; // MPI状态对象,用于接收操作
// 初始化MPI环境
MPI_Init(&argc, &argv);
// 获取当前进程在通信域中的排名(ID)
MPI_Comm_rank(MPI_COMM_WORLD, &taskid);
// 获取通信域中的进程总数
MPI_Comm_size(MPI_COMM_WORLD, &numtasks);
/* 需要偶数个进程才能正常运行 */
if (numtasks % 2 != 0) {
if (taskid == MASTER)
printf("Quitting. Need an even number of tasks: numtasks=%d\n", numtasks);
}
else {
// 主进程打印总进程数
if (taskid == MASTER)
printf("MASTER: Number of MPI tasks is: %d\n",numtasks);
// 获取并打印当前进程运行的处理器名称
MPI_Get_processor_name(hostname, &len);
printf ("Hello from task %d on %s!\n", taskid, hostname);
/* 确定通信伙伴并进行消息交换 */
// 前半部分进程(0 到 numtasks/2-1)的通信逻辑
if (taskid < numtasks/2) {
partner = numtasks/2 + taskid; // 伙伴是后半部分的对应进程
// 先发送自己的rank给伙伴
MPI_Send(&taskid, 1, MPI_INT, partner, 1, MPI_COMM_WORLD);
// 然后接收伙伴发送过来的rank
MPI_Recv(&message, 1, MPI_INT, partner, 1, MPI_COMM_WORLD, &status);
}
// 后半部分进程(numtasks/2 到 numtasks-1)的通信逻辑
else if (taskid >= numtasks/2) {
partner = taskid - numtasks/2; // 伙伴是前半部分的对应进程
// 先接收伙伴发送过来的rank
MPI_Recv(&message, 1, MPI_INT, partner, 1, MPI_COMM_WORLD, &status);
// 然后发送自己的rank给伙伴
MPI_Send(&taskid, 1, MPI_INT, partner, 1, MPI_COMM_WORLD);
}
/* 打印伙伴信息并退出 */
printf("Task %d is partner with %d\n",taskid,message);
}
// 终止MPI环境
MPI_Finalize();
return 0; // 程序正常退出
}
编译运行命令:
mpicc test.c -o test
mpirun -np 4 ./test
预期输出:
Hello from task 2 on <hostname>!
Hello from task 1 on <hostname>!
Hello from task 3 on <hostname>!
Task 1 is partner with 3
Task 3 is partner with 1
MASTER: Number of MPI tasks is: 4
Hello from task 0 on <hostname>!
Task 0 is partner with 2
Task 2 is partner with 0
非阻塞型
代码:
#include "mpi.h" // MPI头文件
#include <stdio.h> // 标准输入输出头文件
#include <stdlib.h> // 标准库头文件
#define MASTER 0 // 定义主进程的rank为0
int main (int argc, char *argv[])
{
int numtasks, // MPI任务总数(进程数)
taskid, // 当前任务的排名(进程ID)
len; // 处理器名称长度
char hostname[MPI_MAX_PROCESSOR_NAME]; // 存储处理器名称的数组
int partner, // 通信伙伴的进程排名
message; // 接收到的消息内容(伙伴的rank)
MPI_Status stats[2]; // MPI状态对象数组,用于Waitall操作
MPI_Request reqs[2]; // 非阻塞操作请求句柄数组
// 初始化MPI环境
MPI_Init(&argc, &argv);
// 获取当前进程在通信域中的排名(ID)
MPI_Comm_rank(MPI_COMM_WORLD,&taskid);
// 获取通信域中的进程总数
MPI_Comm_size(MPI_COMM_WORLD, &numtasks);
/* 需要偶数个进程才能正常运行 */
if (numtasks % 2 != 0) {
if (taskid == MASTER)
printf("Quitting. Need an even number of tasks: numtasks=%d\n", numtasks);
}
else {
// 获取并打印当前进程运行的处理器名称
MPI_Get_processor_name(hostname, &len);
printf ("Hello from task %d on %s!\n", taskid, hostname);
// 主进程打印总进程数
if (taskid == MASTER)
printf("MASTER: Number of MPI tasks is: %d\n",numtasks);
/* 确定通信伙伴 */
// 前半部分进程(0 到 numtasks/2-1)的伙伴是后半部分的对应进程
if (taskid < numtasks/2)
partner = numtasks/2 + taskid;
// 后半部分进程(numtasks/2 到 numtasks-1)的伙伴是前半部分的对应进程
else if (taskid >= numtasks/2)
partner = taskid - numtasks/2;
// 发布非阻塞接收操作:从伙伴进程接收一个整数
MPI_Irecv(&message, 1, MPI_INT, partner, 1, MPI_COMM_WORLD, &reqs[0]);
// 发布非阻塞发送操作:向伙伴进程发送自己的rank
MPI_Isend(&taskid, 1, MPI_INT, partner, 1, MPI_COMM_WORLD, &reqs[1]);
/* 等待所有非阻塞操作完成 */
// 阻塞在此,直到发送和接收两个请求都完成
MPI_Waitall(2, reqs, stats);
/* 打印伙伴信息并退出*/
printf("Task %d is partner with %d\n",taskid,message);
}
// 终止MPI环境
MPI_Finalize();
return 0; // 程序正常退出
}
编译运行命令:
mpicc test.c -o test
mpirun -np 4 ./test
预期输出:
Hello from task 2 on <hostname>!
Hello from task 1 on <hostname>!
Hello from task 3 on <hostname>!
Task 1 is partner with 3
Task 3 is partner with 1
MASTER: Number of MPI tasks is: 4
Hello from task 0 on <hostname>!
Task 0 is partner with 2
Task 2 is partner with 0
2377

被折叠的 条评论
为什么被折叠?



