【MPI】实现进程间环形通讯

1. 问题描述

创建np个进程,使第iam个进程向iam+1个进程发送消息,第np-1个进程向第0个进程发送消息,行成一个环形结构

2. 解决思路

申明一个子程序

/************************************************* 
Function:       ring
Description:    实现进程间环形通讯 
Input:          m: 发送的消息
                comm:MPI通讯域
                np: 进程数
                iam:当前进程号 
Output:         n:接收的消息
Return:         void
*************************************************/  
void ring(int m, int *n, MPI_Comm comm, int np, int iam);

2.1 定位前后进程

已知第iam个进程,定位前一个进程。为了防止第0个进程减1后得到负数,需要加上np

front = (np + iam - 1) % np;

已知第iam个进程,定位下一个进程,为了使第np-1个进程的下一个进程为0,需要取模

next = (iam + 1) % np;

2.2 消息发送

思路一

使用MPI_SendMPI_Recv。这对函数是阻塞式操作,为了防止死锁,需要有进程先发送消息。最直观的思路是0号进程先发送再接收,其他进程先接收再发送。但这样几乎没有并行性,效率太低;考虑让偶数号进程先发送,奇数号进程先接收

if (iam % 2 == 0){ // 让做一半进程先发送,一半进程再接收
		MPI_Send(&m, 1, MPI_INT, next, 1, comm);
		MPI_Recv(n, 1, MPI_INT, front, 1, comm, &status);
	}
	else{ //一定要有进程在发送之前要先接收偶数进程的消息
		MPI_Recv(n, 1, MPI_INT, front, 1, comm, &status);
		MPI_Send(&m, 1, MPI_INT, next, 1, comm);
	}

思路二

使用MPI_IsendMPI_Irecv。这对函数是非阻塞式操作,因此不会出现死锁,但是可能有的进程消息还没有收到就直接退出的情况,因此需要使用MPI_Wait同步进程。

同步的思路很灵活,既可以等待发送和接收都完成,也可以只等待接收操作完成

MPI_Status status[2];
MPI_Request reqs[2];
MPI_Isend(&m, 1, MPI_INT, next, 1, comm, &reqs[0]);
MPI_Irecv(n, 1, MPI_INT, front, 1, comm, &reqs[1]);
//MPI_Waitall(2, reqs, status); // 等待发送和接收都完成
MPI_Wait(&reqs[1], &status[1]); // 仅等待接收完成

思路三

使用MPI_Sendrecv,该函数整合sendrecv操作,认为sendrecv操作组合是阻塞的,而sendrecv之间又是没有顺序的

MPI_Sendrecv(&m, 1, MPI_INT, next, 1, \
		n, 1, MPI_INT, front, 1, comm, &status);

2.3 主程序

int main(int argc, char *argv[])
{
	// my begin
	int rank;
	int numtasks;

	MPI_Init(&argc, &argv); /*Initializes MPI calls*/
	MPI_Comm_rank(MPI_COMM_WORLD, &rank);     /* obtains the rank of current MPI process */
	MPI_Comm_size(MPI_COMM_WORLD, &numtasks); /* obtains the total number of MPI processes */

	// my function
	int m = rank, n = 100; //m:发送数据,n:接收数据
	ring(m, &n, MPI_COMM_WORLD, numtasks, rank);
	cout << "My rank:" << rank << "\tMy n:" << n;

	// my end
	MPI_Finalize();        /*Finalizes MPI calls */
	return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章