将 MPI 消息从 C++ 代码发送到 Fortran 90 代码

send mpi message from a c++ code to fortran 90 code

本文关键字:代码 Fortran 消息 C++ MPI      更新时间:2023-10-16

我正在尝试查看是否可以将c ++代码中的数组内容发送到fortran 90代码。我使用的是使用英特尔 11.1.072 编译器构建的 openmpi 1.4.3。它们安装在 Linux 版本 2.6.18-108chaos (mockbuild@chaos4builder1) (gcc 版本 4.1.2 20080704 (Red Hat 4.1.2-48)) 上。

这是 c++ 方面:

# include <cstdlib>
# include <iostream>
# include <mpi.h>
using namespace std;
void printarray (float arg[], int length) {
   for (int n=0; n<length; n++)
    cout << arg[n] << " ";
  cout << "n";
}
int main(int argc, char *argv[] ){
   float a[10];
   int myrank,i;
   MPI::Init ( argc, argv );
   myrank=MPI::COMM_WORLD.Get_rank();
   cout << "rank "<<myrank<<" is c++ rank."<<std::endl;
   for (i=0;i<10;i++){
      a[i]=10.0;
   }
   printarray(a,10);
   MPI::COMM_WORLD.Send(&a[0],1,MPI::DOUBLE_PRECISION,1,100);
   MPI::Finalize();
}

这是 F90 方面:

program main
implicit none
include "mpif.h"
integer:: ierr,stat(MPI_STATUS_SIZE)
real(8):: a(10)
call mpi_init(ierr)
a=0
print*,a
call mpi_recv(a(1),10,MPI_DOUBLE_PRECISION,0,100,MPI_COMM_WORLD,stat,ierr)
print*,a
call mpi_finalize(ierr)
end program

编译完两个代码后,我运行

$mpirun -n 1 *c_executable* : -n 1 *fortran_executable* > output

我在 fortran 方面得到的数字不是 10.0。

MPI 标准确实有语言互操作性的规定 - MPI 2.2 文档的整个 §16.3 专门用于 Fortran 和 C 之间的语言互操作性。

§16.3.10 跨语言交流

MPI anr 中通信的类型缓存规则未更改:发送的每个项目的数据类型规范应在类型签名中与用于接收此项目的数据类型规范匹配(除非其中一种类型是 MPI_PACKED )。此外,消息项的类型应与相应通信缓冲区位置的类型声明匹配,除非类型为 MPI_BYTEMPI_PACKED 。如果符合这些规则,则允许跨语言交流。

然后,它继续展示一个示例,其中使用相同的构造数据类型从 Fortran 代码发送消息并以一段 C 代码接收它。构造该类型是为了允许 C 代码将数据接收到属于 Fortran 代码的缓冲区中,但与您的问题更相关的是 C 代码使用从 Fortran MPI_REAL构造的数据类型。如果在 C 函数中使用 Fortran 数据类型,反之亦然,如果有意义,这是完全合法的:

§16.3.6 MPI 不透明对象 - 数据类型

。如果用一种语言定义的数据类型用于另一种语言的通信调用,则发送的消息将与从第一种语言发送的消息相同:访问相同的通信缓冲区,并在需要时执行相同的表示转换。所有预定义的数据类型都可以在任何语言的数据类型构造函数中使用。如果提交数据类型,则可以将其用于任何语言的通信。

(预定义的 MPI 数据类型(如 MPI_REALMPI_DOUBLE)已提交)

相反,允许一方面使用 Fortran 数据类型,另一方面使用 C 数据类型,但认为不可移植:

§16.3.10 跨语言交流

。MPI 实现可能会削弱这些类型匹配规则,并允许使用 Fortran 类型发送消息并使用 C 类型接收消息,反之亦然,当这些类型匹配时。也就是说,如果Fortran类型INTEGER与C类型int相同,那么MPI实现可以允许以数据类型MPI_INTEGER发送数据,并以数据类型MPI_INT接收数据。但是,此类代码不可移植。

(强调我的)

REAL(8)更改为 DOUBLE PRECISION 不会增加代码的可移植性,因为 Fortran 标准不保证DOUBLE PRECISION类型的表示 - 它只说 DOUBLE PRECISION 是一种REAL类型的替代说明符,即双精度类型,它应该比默认的 real 具有更高的十进制精度。发送数据类型为 MPI_DOUBLE_PRECISIONREAL(8)不可移植。相反,可移植程序将使用 Fortran 的SELECTED_REAL_KIND固有函数和 MPI_Type_create_f90_real 来注册匹配的 MPI 数据类型。

恕我直言,最好的选择是依靠 C 和 Fortran 之间的语言互操作性,并坚持在双方使用相同的数据类型。由于您的编译器套件足够新,因此您可以使用 Fortran 的ISO_C_BINDING机制来获取与 C 兼容的REALINTEGER种类,并在 Fortran 调用中使用 C 数据类型。例如:

USE, INTRINSIC :: ISO_C_BINDING
REAL(C_DOUBLE), DIMENSION(10) :: darray
INTEGER(C_INT) :: ival
...
CALL MPI_SEND(darray, 10, MPI_DOUBLE, 0, 0, MPI_COMM_WORLD, ierr)
CALL MPI_BCAST(ival, 1, MPI_INT, 0, MPI_COMM_WORLD, ierr)
...

是的,你可以这样做;主要问题是在你的C++代码中,你的a数组是 float 类型,而不是双精度。

你也只发送这些非双精度值中的 1 个,而不是 10 个;MPI_RECV()仍然有效,但当然其他 9 个值不会被设置。

你应该注意的另一件事是,你应该在 C/C++ 中使用 MPI_DOUBLE,在 Fortran 中使用MPI_DOUBLE_PRECISION;它们不需要相同,事实上,我想在 C 中使用 MPI_DOUBLE_PRECISION 是不确定的。

您可能还想在 fortran 程序中使用 double precision 而不是 real(8) ,这很常见,但不是标准的。

原则上,您甚至要担心异构性,担心运行这两个程序的机器上浮点数的编码,但对于我们大多数人来说,这不是问题。

这是 C 语言中修改的工作版本

#include <stdio.h>
#include <mpi.h>
main(int argc, char **argv) 
{
  int i,ierr, num_procs, my_id;
  double a[10];
  for (i=0;i<10;i++)
  {
    a[i]=10.0;
  }
  ierr = MPI_Init(&argc, &argv);
  printf(" Hello C Coden"); 
  /**/
  ierr = MPI_Comm_rank(MPI_COMM_WORLD, &my_id);
  ierr = MPI_Comm_size(MPI_COMM_WORLD, &num_procs);
  ierr = MPI_Send(&a[0],10,MPI_DOUBLE,1,100, MPI_COMM_WORLD);  

  ierr = MPI_Finalize(); 
}

这是 F 中的修改工作版本

    program main
        use mpi
        implicit none
        integer:: ierr,stat(MPI_STATUS_SIZE)
        double precision:: a(10)
        call mpi_init(ierr)
        write(*,*)"Hello F Code"
        a=0
        print*,a
        call mpi_recv(a(1),10,MPI_DOUBLE_PRECISION,0,100,MPI_COMM_WORLD,stat,ierr)
        print*,a
        call mpi_finalize(ierr)
    end program