C 我的代码中有一个关于线性过程计算的互锁

C 我的代码中有一个关于线性过程计算的互锁,c,linux,process,mpi,C,Linux,Process,Mpi,我们假设我们有一个n个线性进程P1…P2,每个进程都会与它的邻居(左和右)通信,我们有一个大小为n的向量X,& 席=(X-1+席+席+1)/4和0<i=世界大小){ up=MPI\U PROC\U NULL; } 如果(down要理解死锁,请想象一下如果使用两个进程,死锁将如何运行:两个进程都将调用MPI_Send(),并且它们都不会接收消息,因为MPI_Send()正在阻塞 因此,要克服此问题,必须接收消息!有多种解决方案: 正如Hristo Iliev所建议的,您可以使用。事实上,OpenM

我们假设我们有一个n个线性进程P1…P2,每个进程都会与它的邻居(左和右)通信,我们有一个大小为n的向量X,& 席=(X-1+席+席+1)/4和0<i
 #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]);*/

}
#包括
#包括
#包括
int main(int argc,char*argv[]){
国际世界排名;
国际大世界;
双rec=0,rec2=0;
int i,j;
MPI_Init(&argc,&argv);
MPI通信等级(MPI通信世界级和世界级);
MPI_Comm_大小(MPI_Comm_WORLD和WORLD_大小);
双x[世界尺寸];

对于(i=0;i要理解死锁,请想象一下如果使用两个进程,死锁将如何运行:两个进程都将调用
MPI\u Send()
,并且它们都不会接收消息,因为
MPI\u Send()
正在阻塞

因此,要克服此问题,必须接收消息!有多种解决方案:

  • 正如Hristo Iliev所建议的,您可以使用。事实上,OpenMPI cleary的文档将您的情况称为
    Sendrecv()
  • MPI_Sendrecv()
    在一次调用中,将消息发送到一个目的地和从另一个进程接收另一个消息结合在一起。发送-接收操作对于在一系列进程中执行移位操作非常有用。如果将阻止发送和接收用于此类移位,则需要对发送和接收进行正确排序(例如,偶数进程先发送,然后接收;奇数进程先接收,然后发送)以防止可能导致死锁的循环依赖关系

    下面说明了此选项

  • 非阻塞通信可以通过函数和使用。但是必须有对函数的调用,如确保所有消息都被实际发送和接收

    #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;
    }
    
    #包括
    #包括
    #包括
    int main(int argc,char*argv[])
    {
    int世界大小、世界排名;
    MPI_Init(&argc,&argv);
    MPI_Comm_大小(MPI_Comm_WORLD和WORLD_大小);
    MPI通信等级(MPI通信世界级和世界级);
    INTX[世界大小];
    x[世界排名]=世界排名;
    int up=世界排名+1;
    int down=世界排名第一;
    如果(向上>=世界大小){
    up=MPI\U PROC\U NULL;
    }
    
    如果(down要理解死锁,请想象一下如果使用两个进程,死锁将如何运行:两个进程都将调用
    MPI_Send()
    ,并且它们都不会接收消息,因为
    MPI_Send()
    正在阻塞

    因此,要克服此问题,必须接收消息!有多种解决方案:

  • 正如Hristo Iliev所建议的,您可以使用。事实上,OpenMPI cleary的文档将您的情况称为
    Sendrecv()
  • MPI_Sendrecv()
    在一次调用中,将消息发送到一个目的地和从另一个进程接收另一个消息结合在一起。发送-接收操作对于在一系列进程中执行移位操作非常有用。如果将阻止发送和接收用于此类移位,则需要对发送和接收进行正确排序(例如,偶数进程先发送,然后接收;奇数进程先接收,然后发送)以防止可能导致死锁的循环依赖关系

    下面说明了此选项

  • 非阻塞通信可以通过函数和使用。但是必须有对函数的调用,如确保所有消息都被实际发送和接收

    #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;
    }
    
    #包括
    #包括
    #包括
    int main(int argc,char*argv[])
    {
    int世界大小、世界排名;
    MPI_Init(&argc,&argv);
    MPI_Comm_大小(MPI_Comm_WORLD和WORLD_大小);
    MPI通信等级(MPI通信世界级和世界级);
    INTX[世界大小];
    x[世界排名]=世界排名;
    int up=世界排名+1;
    int down=世界排名第一;
    如果(向上>=世界大小){
    up=MPI\U PROC\U NULL;
    }
    
    如果(使用
    MPI\u Sendrecv
    来防止死锁。我如何使用它?使用
    MPI\u Sendrecv
    来防止死锁。我如何使用它?几乎可以保证单个整数的发送被缓冲。真正的问题是,中间列的代码从一对阻塞接收和tho开始在左右消息到达之前,se无法返回。此外,您不需要使发送和接收都无阻塞,只需要逻辑上的第一组操作。在您的情况下,这将是
    MPI_Isend
    ,然后是
    MPI_Recv
    ,然后是
    MPI_Waitall
    。顺便说一句,在openm中,
    MPI_Sendrecv
    PI被实现为
    MPI_Irecv
    /
    MPI_Send
    /
    MPI_Wait
    。看看我的答案,试试那个代码,告诉我为什么?@hristoilev:谢谢你的启发性反馈!事实上,如果使用两个或三个进程,代码不会冻结,可能是因为使用了缓冲发送模式。thanx很多,我知道很晚了,但thanx一个整数的结尾几乎可以保证是缓冲的。真正的问题是,中间列组的代码以一对阻塞接收开始,而这些代码在左右消息到达之前无法返回。此外,您不需要使发送和接收都是非阻塞的,只需要逻辑上的第一组ope口粮。在你的情况下,这将是
    MPI_Isend
    然后是
    MPI_Recv
    然后是
    MPI_Waitall
    。顺便说一句,
    MPI_Sendrecv
    在开放式MPI中实现为
    MPI_Irecv
    /
    MPI_Send
    /
    MPI_Wait
    。看看我的答案,试试那个代码,告诉我为什么?@hriliev:谢谢你的回复启示反馈!事实上,如果使用两个或三个进程,代码不会冻结,可能是因为使用了缓冲发送模式。thanx a