我的代码中有一个关于线性过程计算的阻塞
I have an interblockage in my code which is about linear process calculation
我们假设我们有一个 n 线性过程 P1...P2 ,每个过程都会与他的邻居(左和右)进行通信,并且我们有一个大小为 n 的向量 X ,&
Xi= (X-1 + Xi + Xi+1 )/4 & 0< i < n-1
在这种情况下,每个进程 i 将数据 Xi 发送到他的邻居 Xi+1 & Xi-1 并从 i-1 & i+1 接收 Xi-1 & Xi+1 ,以计算 Xi
的新值
这就是我所做的,但我有一个中间阻塞,所以请帮助找出错误:
#include<stdio.h>
#include<mpi.h>
#include <unistd.h>
int main(int argc, char *argv[]){
int world_rank;
int world_size;
double rec=0,rec2=0;
int i,j;
MPI_Init (&argc, &argv);
MPI_Comm_rank(MPI_COMM_WORLD,&world_rank);
MPI_Comm_size(MPI_COMM_WORLD,&world_size);
double x[world_size];
for(i=0;i<world_size;i++)x[i]=i;
for(i=0;i<world_size;i++){
if(world_rank==i){
if(world_rank==0){
int a1=MPI_Send(&x[i],1,MPI_INT,i+1,0,MPI_COMM_WORLD);
int a2=MPI_Recv(&rec,1,MPI_INT,i+1,0,MPI_COMM_WORLD,MPI_STATUS_IGNORE);
if((a1==MPI_SUCCESS)&&(a2==MPI_SUCCESS)){
x[i]=(x[i]+rec)/4;
printf("x[%d]= %f\n",i,x[i]);
}
}else if(world_rank==world_size-1){
int a4=MPI_Send(&x[i],1,MPI_INT,i-1,0,MPI_COMM_WORLD);
int a3=MPI_Recv(&rec,1,MPI_INT,i-1,0,MPI_COMM_WORLD,MPI_STATUS_IGNORE);
if((a3==MPI_SUCCESS)&&(a4==MPI_SUCCESS)){
x[i]=(x[i]+rec)/4;
printf("x[%d]= %f\n",i,x[i]);
}
}else{
int a7=MPI_Recv(&rec,1,MPI_INT,i+1,0,MPI_COMM_WORLD,MPI_STATUS_IGNORE);
int a8=MPI_Recv(&rec2,1,MPI_INT,i-1,0,MPI_COMM_WORLD,MPI_STATUS_IGNORE);
int a5=MPI_Send(&x[i],1,MPI_INT,i+1,0,MPI_COMM_WORLD);
int a6=MPI_Send(&x[i],1,MPI_INT,i-1,0,MPI_COMM_WORLD);
if((a5==MPI_SUCCESS)&&(a5==MPI_SUCCESS)&&(a5==MPI_SUCCESS)&&(a5==MPI_SUCCESS)){
x[i]=(x[i]+x[i+1]+x[i-1])/4;
printf("x[%d]= %f\n",i,x[i]);
}
}
}
}
/*for(i=0;i<world_size;i++)
printf("x[%d]= %f\n",i,x[i]);*/
}
要理解死锁,想象一下如果使用两个进程会如何 运行:两个进程都会调用 MPI_Send()
,其中 none 会收到消息,因为 MPI_Send()
正在阻塞。
因此,要克服这个问题,必须接收消息!有许多可用的解决方案:
- 根据 Hristo Iliev 的建议,您可以使用
MPI_Sendrecv()
。实际上,OpenMPI cleary 的文档将您的情况称为 Sendrecv()
: 的典型用法
MPI_Sendrecv()
combines in one call the sending of a message to one destination and the receiving of another message, from another process. A send-receive operation is useful for executing a shift operation across a chain of processes. If blocking sends and receives are used for such a shift, then one needs to order the sends and receives correctly (for example, even processes send, then receive; odd processes receive first, then send) in order to prevent cyclic dependencies that may lead to deadlock.
以下 example 说明了此选项。
可以通过函数MPI_Isend()
and MPI_Irecv()
. But there must be a call to a function like MPI_Waitall()
使用非阻塞通信来保证所有的消息都真实的发送和接收。
#include <mpi.h>
#include <stdio.h>
#include <stdlib.h>
int main(int argc,char *argv[])
{
int world_size, world_rank;
MPI_Init(&argc,&argv);
MPI_Comm_size(MPI_COMM_WORLD,&world_size);
MPI_Comm_rank(MPI_COMM_WORLD,&world_rank);
int x[world_size];
x[world_rank]=world_rank;
int up=world_rank+1;
int down=world_rank-1;
if(up>=world_size){
up=MPI_PROC_NULL;
}
if(down<0){
down=MPI_PROC_NULL;
}
MPI_Request req[4];
MPI_Isend(&x[world_rank], 1, MPI_INT, up, 0, MPI_COMM_WORLD, &req[0]);
MPI_Isend(&x[world_rank], 1, MPI_INT, down, 0, MPI_COMM_WORLD, &req[1]);
MPI_Irecv(&x[(world_rank-1+world_size)%world_size], 1, MPI_INT, down, 0, MPI_COMM_WORLD, &req[2]);
MPI_Irecv(&x[(world_rank+1+world_size)%world_size], 1, MPI_INT, up, 0, MPI_COMM_WORLD, &req[3]);
MPI_Waitall(4, req, MPI_STATUSES_IGNORE);
printf("rank %d has %d %d %d\n",world_rank,x[(world_rank-1+world_size)%world_size],x[world_rank],x[(world_rank+1+world_size)%world_size]);
MPI_Finalize();
return 0;
}
由 mpicc main.c -o main -Wall
编译,运行 由 mpirun -np 10 main
编译。
我们假设我们有一个 n 线性过程 P1...P2 ,每个过程都会与他的邻居(左和右)进行通信,并且我们有一个大小为 n 的向量 X ,& Xi= (X-1 + Xi + Xi+1 )/4 & 0< i < n-1 在这种情况下,每个进程 i 将数据 Xi 发送到他的邻居 Xi+1 & Xi-1 并从 i-1 & i+1 接收 Xi-1 & Xi+1 ,以计算 Xi
的新值这就是我所做的,但我有一个中间阻塞,所以请帮助找出错误:
#include<stdio.h>
#include<mpi.h>
#include <unistd.h>
int main(int argc, char *argv[]){
int world_rank;
int world_size;
double rec=0,rec2=0;
int i,j;
MPI_Init (&argc, &argv);
MPI_Comm_rank(MPI_COMM_WORLD,&world_rank);
MPI_Comm_size(MPI_COMM_WORLD,&world_size);
double x[world_size];
for(i=0;i<world_size;i++)x[i]=i;
for(i=0;i<world_size;i++){
if(world_rank==i){
if(world_rank==0){
int a1=MPI_Send(&x[i],1,MPI_INT,i+1,0,MPI_COMM_WORLD);
int a2=MPI_Recv(&rec,1,MPI_INT,i+1,0,MPI_COMM_WORLD,MPI_STATUS_IGNORE);
if((a1==MPI_SUCCESS)&&(a2==MPI_SUCCESS)){
x[i]=(x[i]+rec)/4;
printf("x[%d]= %f\n",i,x[i]);
}
}else if(world_rank==world_size-1){
int a4=MPI_Send(&x[i],1,MPI_INT,i-1,0,MPI_COMM_WORLD);
int a3=MPI_Recv(&rec,1,MPI_INT,i-1,0,MPI_COMM_WORLD,MPI_STATUS_IGNORE);
if((a3==MPI_SUCCESS)&&(a4==MPI_SUCCESS)){
x[i]=(x[i]+rec)/4;
printf("x[%d]= %f\n",i,x[i]);
}
}else{
int a7=MPI_Recv(&rec,1,MPI_INT,i+1,0,MPI_COMM_WORLD,MPI_STATUS_IGNORE);
int a8=MPI_Recv(&rec2,1,MPI_INT,i-1,0,MPI_COMM_WORLD,MPI_STATUS_IGNORE);
int a5=MPI_Send(&x[i],1,MPI_INT,i+1,0,MPI_COMM_WORLD);
int a6=MPI_Send(&x[i],1,MPI_INT,i-1,0,MPI_COMM_WORLD);
if((a5==MPI_SUCCESS)&&(a5==MPI_SUCCESS)&&(a5==MPI_SUCCESS)&&(a5==MPI_SUCCESS)){
x[i]=(x[i]+x[i+1]+x[i-1])/4;
printf("x[%d]= %f\n",i,x[i]);
}
}
}
}
/*for(i=0;i<world_size;i++)
printf("x[%d]= %f\n",i,x[i]);*/
}
要理解死锁,想象一下如果使用两个进程会如何 运行:两个进程都会调用 MPI_Send()
,其中 none 会收到消息,因为 MPI_Send()
正在阻塞。
因此,要克服这个问题,必须接收消息!有许多可用的解决方案:
- 根据 Hristo Iliev 的建议,您可以使用
MPI_Sendrecv()
。实际上,OpenMPI cleary 的文档将您的情况称为Sendrecv()
: 的典型用法
MPI_Sendrecv()
combines in one call the sending of a message to one destination and the receiving of another message, from another process. A send-receive operation is useful for executing a shift operation across a chain of processes. If blocking sends and receives are used for such a shift, then one needs to order the sends and receives correctly (for example, even processes send, then receive; odd processes receive first, then send) in order to prevent cyclic dependencies that may lead to deadlock.
以下 example 说明了此选项。
可以通过函数
MPI_Isend()
andMPI_Irecv()
. But there must be a call to a function likeMPI_Waitall()
使用非阻塞通信来保证所有的消息都真实的发送和接收。#include <mpi.h> #include <stdio.h> #include <stdlib.h> int main(int argc,char *argv[]) { int world_size, world_rank; MPI_Init(&argc,&argv); MPI_Comm_size(MPI_COMM_WORLD,&world_size); MPI_Comm_rank(MPI_COMM_WORLD,&world_rank); int x[world_size]; x[world_rank]=world_rank; int up=world_rank+1; int down=world_rank-1; if(up>=world_size){ up=MPI_PROC_NULL; } if(down<0){ down=MPI_PROC_NULL; } MPI_Request req[4]; MPI_Isend(&x[world_rank], 1, MPI_INT, up, 0, MPI_COMM_WORLD, &req[0]); MPI_Isend(&x[world_rank], 1, MPI_INT, down, 0, MPI_COMM_WORLD, &req[1]); MPI_Irecv(&x[(world_rank-1+world_size)%world_size], 1, MPI_INT, down, 0, MPI_COMM_WORLD, &req[2]); MPI_Irecv(&x[(world_rank+1+world_size)%world_size], 1, MPI_INT, up, 0, MPI_COMM_WORLD, &req[3]); MPI_Waitall(4, req, MPI_STATUSES_IGNORE); printf("rank %d has %d %d %d\n",world_rank,x[(world_rank-1+world_size)%world_size],x[world_rank],x[(world_rank+1+world_size)%world_size]); MPI_Finalize(); return 0; }
由 mpicc main.c -o main -Wall
编译,运行 由 mpirun -np 10 main
编译。