3

我正在尝试查看是否可以将 c++ 代码中的数组内容发送到 fortran 90 代码。我正在使用使用 intel 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。

4

3 回答 3

4

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

§16.3.10 跨语言交流

MPI 中通信的类型匹配规则并没有改变:发送的每个项目的数据类型规范应在类型签名中匹配用于接收该项目的数据类型规范(除非其中一种类型是MPI_PACKED)。此外,消息项的类型应与相应通信缓冲区位置的类型声明相匹配,除非类型为MPI_BYTEor MPI_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 实现可能允许使用 datatype 发送数据MPI_INTEGER并使用 datatype 接收数据MPI_INT然而,这样的代码是不可移植的。

(强调我的)

更改REAL(8)DOUBLE PRECISION不会增加代码的可移植性,因为 Fortran 标准不保证DOUBLE PRECISION类型的表示 - 它只是说这DOUBLE PRECISION是一种REAL类型的替代说明符,即双精度类型,它应该具有更高的小数精度比默认的真实。REAL(8)使用数据类型发送MPI_DOUBLE_PRECISION是不可移植的。相反,可移植程序将使用SELECTED_REAL_KINDFortran 的内在函数以及MPI_Type_create_f90_real注册匹配的 MPI 数据类型。

恕我直言,最好的选择是依靠 C 和 Fortran 之间的语言互操作性,并在双方都坚持相同的数据类型。由于您的编译器套件足够新,您可以使用ISO_C_BINDINGFortran 的机制来获取REALINTEGER种类,与 C 兼容,并在 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)
...
于 2012-08-14T11:07:41.563 回答
1

这是 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 Code\n"); 

  /**/
  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
于 2013-10-18T20:13:46.057 回答
1

是的,你可以这样做;主要问题是在您的 C++ 代码中,您的a数组是 type float,而不是 double 。

您也只发送了 1 个,而不是 10 个,这些非双打;仍然可以MPI_RECV()工作,但当然不会设置其他 9 个值。

您应该注意的其他一点是您应该MPI_DOUBLE在 C/C++ 和MPI_DOUBLE_PRECISIONFortran 中使用;它们不必相同,实际上我想MPI_DOUBLE_PRECISIONC 中的使用是未定义的。

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

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

于 2012-08-14T01:14:29.640 回答