如何防止在 class 析构函数中调用 MPI_Finalize()?

How to prevent calling of MPI_Finalize() within class destructor?

我有一个 class,它在其构造函数中创建一个新的 MPI_Datatype,然后在其析构函数中将其删除。但是,删除自定义数据类型的存在以某种方式触发了析构函数中 MPI_Finalize() 的调用。

#include <cstdio>
#include "mpi.h"

class foo
{
public:
    MPI_Datatype M_INT;

    foo(MPI_Comm comm) 
    {
        MPI_Comm_rank(comm, &id);
        printf("%2d: Constructing foo.\n", id);
        MPI_Type_dup(MPI_INT, &M_INT);
    }
    
    ~foo() 
    {
        printf("%2d: Destructing foo.\n", id);
        MPI_Type_free(&M_INT);                  // problematic line
    }
private:
    int id;
};

int main(int argc, char* argv[])
{
    MPI_Init(&argc, &argv);
    foo bar(MPI_COMM_WORLD);
    MPI_Finalize();
    
    return 0;
}

这会产生运行时错误 Attempting to use an MPI routine after finalizing MPICH。删除析构函数中自定义 MPI_Datatype 的删除是一种临时解决方法。但是,我想要一个更好、更合适的解决方案。如果您知道为什么会发生这种情况以及如何解决,请解释一下。谢谢。


编辑:

根据评论中的建议,我尝试了以下方法。这仍然存在与我之前的示例代码完全相同的问题。

#include <cstdio>
#include "mpi.h"

class M_Comm
{
public:
    MPI_Comm p;
    int already_finalised;

    M_Comm(const MPI_Comm& _comm) : p(_comm) {}
    ~M_Comm()
    {
        MPI_Finalized(&already_finalised);
        if (!already_finalised)
            MPI_Finalize();
    }
};

class foo
{
public:
    MPI_Datatype M_INT;

    foo(const M_Comm& comm) 
    {
        MPI_Comm_rank(comm.p, &id);
        printf("%2d: Constructing foo.\n", id);
        MPI_Type_dup(MPI_INT, &M_INT);
    }
    
    ~foo() 
    {
        printf("%2d: Destructing foo.\n", id);
        MPI_Type_free(&M_INT);                  // problematic line
    }
private:
    int id;
};

int main(int argc, char* argv[])
{
    MPI_Init(&argc, &argv);
    M_Comm comm_std(MPI_COMM_WORLD);
    foo bar(comm_std);
    MPI_Finalize();
    
    return 0;
}

@VictorEijkhout 在他的评论中提出了以下解决方案。这个想法是创建一个在其构造函数和析构函数中调用 MPI_InitMPI_Finalize 的通信对象,然后将该对象传递给其他函数或 类 以进行进一步操作。

#include <cstdio>
#include "mpi.h"

class MPI_Obj
{
public:
    MPI_Comm COMM = MPI_COMM_WORLD;
    int already_finalised;

    MPI_Obj(int argc, char* argv[])
    {
        MPI_Init(&argc, &argv);
    }
    ~MPI_Obj()
    {
        MPI_Finalized(&already_finalised);
        if (!already_finalised)
            MPI_Finalize();
    }
};

class foo
{
public:
    MPI_Datatype M_INT;

    foo(const MPI_Obj& mpi) 
    {
        MPI_Comm_rank(mpi.COMM, &id);
        printf("%2d: Constructing foo.\n", id);
        MPI_Type_dup(MPI_INT, &M_INT);
    }
    
    ~foo() 
    {
        printf("%2d: Destructing foo.\n", id);
        MPI_Type_free(&M_INT);
    }
private:
    int id;
};

int main(int argc, char* argv[])
{
    MPI_Obj comm_std(argc, argv);
    foo bar(comm_std);
    
    return 0;
}