Error handling 在不同的通信器中接收到MPI消息-程序错误或MPI实施错误?

Error handling 在不同的通信器中接收到MPI消息-程序错误或MPI实施错误?,error-handling,mpi,intel-mpi,Error Handling,Mpi,Intel Mpi,这是对的后续行动,其结论是程序错误,因此预期行为未定义 我在这里尝试创建的是一个简单的错误处理机制,为此,我将对空消息的Irecv请求用作“中止句柄”,将其附加到我的正常MPI_Wait调用(并将其转换为MPI_WaitAny),为了允许我在进程0上发生错误时取消阻止进程1,并且它无法再到达应该发布匹配的MPI\u Recv的点 发生的情况是,由于内部消息缓冲,MPI\u Isend可能会立即成功,而另一个进程无法发布匹配的MPI\u Recv。所以再也没有办法取消了 我希望一旦所有进程调用MP

这是对的后续行动,其结论是程序错误,因此预期行为未定义

我在这里尝试创建的是一个简单的错误处理机制,为此,我将对空消息的Irecv请求用作“中止句柄”,将其附加到我的正常
MPI_Wait
调用(并将其转换为
MPI_WaitAny
),为了允许我在进程0上发生错误时取消阻止进程1,并且它无法再到达应该发布匹配的
MPI\u Recv
的点

发生的情况是,由于内部消息缓冲,
MPI\u Isend
可能会立即成功,而另一个进程无法发布匹配的
MPI\u Recv
。所以再也没有办法取消了

我希望一旦所有进程调用
MPI\u Comm\u free
,我就可以一劳永逸地忘记这个消息,但事实并非如此。相反,它被传送到以下通信器中的
MPI\u Recv

因此,我的问题是:

  • 这也是一个错误的程序,还是MPI实现(英特尔MPI 4.0.3)中的一个错误
  • 如果我将我的
    MPI\u Isend
    调用转换为
    MPI\u Issend
    ,程序将按预期工作-在这种情况下,我至少可以确保程序是正确的吗
  • 我是在重新发明轮子吗?有没有更简单的方法来实现这一点
  • 再次感谢您的反馈


    #包括“stdio.h”
    #包括“unistd.h”
    #包括“mpi.h”
    #包括“time.h”
    #包括“stdlib.h”
    int main(int argc,char*argv[]){
    int等级、大小;
    MPI_组;
    MPI_通信我的通信;
    srand(时间(空));
    MPI_Init(&argc,&argv);
    MPI通信等级(MPI通信世界和等级);
    MPI_通信大小(MPI_通信世界和大小);
    MPI通信集团(MPI通信世界和集团);
    MPI通信创建(MPI通信世界、集团和我的通信);
    如果(秩==0)printf(“已创建通讯器%d\n,我的通讯”);
    如果(秩==1){
    MPI_请求请求[2];
    int msg=123,其中:;
    MPI_Isend(&msg,1,MPI_INT,0,0,my_comm,&req[0]);
    MPI_Irecv(NULL,0,MPI_INT,0,0,my_comm,&req[1]);
    MPI_Waitany(2,请求和请求,MPI_状态忽略);
    MPI\u屏障(我的通信);
    if(which==0){
    printf(“排名1:发送成功;取消中止句柄\n”);
    MPI_取消(&req[1]);
    MPI_等待(&req[1],MPI_状态_忽略);
    }否则{
    printf(“排名1:发送中止;取消发送请求\n”);
    MPI_取消(&req[0]);
    MPI_等待(&req[0],MPI_状态_忽略);
    }
    }否则{
    MPI_请求请求;
    int msg,r=rand()%2;
    if(r){
    printf(“等级0:接收消息\n”);
    MPI_Recv(&msg,1,MPI_INT,1,0,my_comm,MPI_STATUS_IGNORE);
    }否则{
    printf(“秩0:发送中止消息\n”);
    MPI_Isend(NULL、0、MPI_INT、1、0、my_comm和req);
    }
    MPI\u屏障(我的通信);
    if(!r){
    MPI_取消(&req);
    MPI\u等待(&req,MPI\u状态\u忽略);
    }
    }
    如果(秩==0)printf(“释放通讯器%d\n,我的通讯”);
    MPI_通信免费(&my_通信);
    睡眠(2);
    MPI通信创建(MPI通信世界、集团和我的通信);
    如果(秩==0)printf(“已创建通讯器%d\n,我的通讯”);
    如果(秩==0){
    MPI_请求请求;
    MPI_状态;
    int msg,取消;
    MPI_Irecv(&msg,1,MPI_INT,1,0,my_comm,&req);
    睡眠(1);
    MPI_取消(&req);
    MPI_等待(&req,&status);
    MPI_测试已取消(&状态,&已取消);
    如果(取消){
    printf(“排名0:接收取消\n”);
    }否则{
    printf(“排名0:收到旧邮件!!!\n”);
    }
    }
    如果(秩==0)printf(“释放通讯器%d\n,我的通讯”);
    MPI_通信免费(&my_通信);
    MPI_Finalize();
    返回0;
    }
    
    产出:

    created communicator -2080374784
    rank 0: sending abort message
    rank 1: send succeed; cancelling abort handle
    freeing communicator -2080374784
    created communicator -2080374784
    rank 0: STRAY MESSAGE RECEIVED!!!
    freeing communicator -2080374784
    

    我尝试使用OpenMPI构建您的代码,但没有成功。mpicc抱怨
    状态。已取消

      error: ‘MPI_Status’ has no member named ‘cancelled’
    
    我想这是英特尔mpi的一项功能。如果您切换为:

        ...
        int flag;
        MPI_Test_cancelled(&status, &flag);
        if (flag) {
        ...
    
    这将使用openmpi提供预期的输出(并减少代码的依赖性)。使用“英特尔mpi”时会出现这种情况吗

    我们需要一位专家告诉我们什么是英特尔mpi中的
    状态。已取消
    ,因为我对此一无所知

    编辑:我测试了我的答案很多次,我发现输出是随机的,有时是正确的,有时不是。对不起。。。好像未设置处于
    状态的内容。部分答案可能在
    MPI\u Wait()

    “仅当MPI例程的返回为MPI_ERR_IN_status时,才会设置状态返回的MPI_ERROR字段。该错误类仅由采用状态参数数组(MPI_Testall、MPI_Testsome、MPI_Waitall和MPI_Waitsome)的例程返回。”。在所有其他情况下,状态中MPI_错误字段的值保持不变。有关确切文本,请参阅MPI-1.1规范中的第3.2.5节。“如果MPI_Test_cancelled()使用MPI_错误,情况可能会变糟


    所以这里有一个技巧:使用
    MPI_Waitall(1,&req,&status)
    !最后输出是正确的

    正如@kraffenetti在上述评论中提到的,这是一个错误的程序,因为发送的消息与接收的消息不匹配。即使消息被取消,它们仍然需要在远程端有一个匹配的接收,因为对于已发送的消息,取消可能不会成功,因为在完成取消之前已经发送了消息(这里就是这种情况)


    这个问题在MPICH的票子上开始了一条线索,您可以在票子上找到更多细节。

    谢谢您的评论!我更新了