【问题标题】:How to pass MPI communicator handle from Fortran to C using iso_c_binding如何使用 iso_c_binding 将 MPI 通信器句柄从 Fortran 传递到 C
【发布时间】:2017-07-20 17:09:30
【问题描述】:

我正在尝试将并行 MPI Fortran 程序链接到也使用 MPI 的并行 C 库。软件架构是以 Fortran 为中心的,所以我试图尽可能多地保留 Fortran 方面。

所以我需要将 C 例程传递给 MPI 通信器的句柄。它们的形式是

  int CFunction(int *something, MPI_Comm *Ccomm)

MPI 带有将 Fortran 转换为 C 通信器句柄的接口:

MPI_Comm MPI_Comm_f2c(MPI_Fint comm)

但是,这些例程应该从 C 中调用,所以现在我必须添加 C 包装函数,我可以将 Fortran 通信器传递给:

int CFunction_FMPI(int *something, MPI_Fint *Fcomm)
{   MPI_Comm Ccomm; int status;
    Ccomm = MPI_Comm_f2c(*Fcomm); // Convert Fortran->C communicator
    status = CFunction(*something,*Ccomm); // Call original function
    return status;
}

然后我必须使用 Fortran 的 C 绑定编写第二个接口——CFunction_FMPI,以允许从 Fortran 调用它。

我的问题是:有没有更好的方法来做到这一点,即避免使用 Fortran->C 通信器转换的 C 包装器?我认为直接从 Fortran 调用MPI_Comm_f2c 并将结果存储在type(c_ptr)integer(c_int) 变量中是最好的,但我无法做到这一点,因为MPI_Comm 之间没有直接/通用的绑定类型和 Fortran。

【问题讨论】:

    标签: c fortran mpi fortran-iso-c-binding fortran2003


    【解决方案1】:

    不,我认为没有比这更好的方法了。我会担心它并没有那么复杂。您可以查看我使用的类似功能

    https://github.com/LadaF/PoisFFT/blob/master/src/f_mpi_comm_c2f.c

    它与您的CFunction_FMPI 方向相反,只是翻译通讯器。它是从 C 到 Fortran。

    // This function is callable from Fortran. MPI_Comm_c2f itself may be just a macro.
    
    MPI_Fint f_MPI_Comm_c2f(MPI_Comm *comm) {
      return MPI_Comm_c2f(*comm);
    }
    

    它不是从 Fortran 中调用的

    interface
        integer function MPI_Comm_c2f(c_handle) bind(C, name="f_MPI_Comm_c2f")
          use iso_c_binding
          type(c_ptr), value :: c_handle
        end function
    end interface
    

    重要的一点是MPI_Comm_c2f 在某些 MPI 库中是一个 C 宏,而不是函数,因此您不能真正从 Fortran 中调用它。我很确定MPI_Comm_f2c 也可以作为宏,因此您不能从 Fortran 中调用它。


    您可以做的是创建一个 Fortran 函数,它只调用 MPI_Comm_f2c 的 C 包装器,然后使用 bind(C) 接口在 Fortran 中调用您的 C 函数

    status = CFunction(something, c_comm)
    

    从而避免为每个 C 函数创建包装器。你只需要一个 Fortran 接口块就可以了。

    问题是你在 Fortran* 中没有MPI_Comm(实际上它是一个指针或一个 int)所以你必须使用一个不透明的指针。

    MPI_Comm* f_MPI_Comm_f2c(MPI_Fint Fcomm)
    {   MPI_Comm* Ccomm;
        Ccomm = malloc(sizeof(MPI_Comm));
        *Ccomm = MPI_Comm_f2c(Fcomm);
        return Ccomm;
    }
    

    返回一个不透明的指针type(c_ptr)。 (检查潜在的 C 编码错误,我什至忘了使用分号。)

    您不止一次将 Fortran 通信器转换为指向 C 通信器的指针。

     type(c_ptr) :: c_comm
     c_comm = f_MPI_Comm_f2c(comm)
    

    * MPI-3 中有一个派生类型type(MPI_Comm),但它包含一个整数部分,无论如何都必须由转换例程转换。

    【讨论】:

    • 感谢@vladimir-f,您的方法效果很好。实际上,在代码中只调用一次f_MPI_Comm_f2c 函数可以避免无聊的 C 指针分配/释放。如果 Fortran 能够像 C++ 一样提供面向对象的 MPI 封装,那就太好了……
    • 实际上,C++ MPI 绑定已被弃用。现代 Fortran 2008 绑定是向前迈出的一大步。
    • 是的,但是来自 MPI 实现的 .mod 文件的使用将始终依赖于编译器,不是吗?由于 .mod 格式尚未标准化,因此相应的 C 标头将是
    • 那是另一回事。 C++ ABI 也不是独立于编译器的。如果您暗示您仍在使用mpif.h,这确实不是一个好主意。如果 MPI 是为不同的编译器编译的,即使您设法编译,您仍然可能会遇到令人不快的意外。
    猜你喜欢
    • 2019-01-04
    • 1970-01-01
    • 2014-10-25
    • 2022-08-23
    • 1970-01-01
    • 1970-01-01
    • 2014-10-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多