要发送该结构的一个元素,只需使用MPI_TYPE_CREATE_STRUCT 创建结构化数据类型proceed as usual。根据程序的堆和堆栈的相对位置,B(1) 相对于N 的偏移量最终可能是一个巨大的正数或负数,但这在大多数 Unix 上都没有问题平台和数字应该在INTEGER(KIND=MPI_ADDRESS_KIND)的范围内。
重要提示:结构的单独实例很可能具有不同的 B 相对于 N 的偏移量,因此 MPI 数据类型只能用于发送用于发送的特定记录在数据类型的构造过程中获取偏移量。
当我尝试使用 MPI_TYPE_CREATE_STRUCT 为此类 Struct 创建派生数据类型时,不同的 CPU 会创建不一致的派生数据类型。这是因为相对于第一个成员 Struct%N,Struct%B(:) 可能位于不同的内存位置,在不同的 CPU 上。
这不是问题。通信操作双方的 MPI 数据类型只能是全等的,这意味着它们应该由相同顺序的相同基本数据类型组成。 每个元素的偏移量无关。 换句话说,只要发送者和接收者在MPI_TYPE_CREATE_STRUCT调用中指定相同类型和数量的数据元素,程序就会正常运行。
要发送多个元素,事情会变得有点复杂。有两种解决方案:
使用MPI_PACK 序列化发送方的数据,使用MPI_UNPACK 反序列化接收方的数据。由于打包和解包需要额外的缓冲区空间,这会使程序的内存需求增加一倍。
或
为每条记录创建一个单独的 MPI 结构数据类型,然后创建一个组合所有记录的结构数据类型。下面是一个示例,说明如何发送包含两个此类结构的数组,一个在 B 中包含 10 个元素,一个包含 20 个元素:
TYPE(Struct) :: Structs(2)
ALLOCATE(Structs(1)%B(10))
ALLOCATE(Structs(2)%B(20))
! (1) Create a separate structure datatype for each record
DO i=1,2
CALL MPI_GET_ADDRESS(Structs(i)%N, POS_(1), IError)
CALL MPI_GET_ADDRESS(Structs(i)%A, POS_(2), IError)
CALL MPI_GET_ADDRESS(Structs(i)%B(1), POS_(3), IError)
Offsets = POS_ - POS_(1)
Types(1) = MPI_INTEGER
Types(2) = MPI_REAL8
Types(3) = MPI_REAL8
Blocks(1) = 1
Blocks(2) = 1
Blocks(3) = i * 10
CALL MPI_TYPE_CREATE_STRUCT(3, Blocks, Offsets, Types, Elem_Type(i), IError)
END DO
! (2) Create a structure of structures that describes the whole array
CALL MPI_GET_ADDRESS(Structs(1)%N, POS_(1), IError)
CALL MPI_GET_ADDRESS(Structs(2)%N, POS_(2), IError)
Offsets = POS_ - POS_(1)
Types(1) = Elem_Type(1)
Types(2) = Elem_Type(2)
Blocks(1) = 1
Blocks(2) = 1
CALL MPI_TYPE_CREATE_STRUCT(2, Blocks, Offsets, Types, TwoElem_Type, IError)
CALL MPI_TYPE_COMMIT(TwoElem_Type, IError)
! (2.1) Free the intermediate datatypes
DO i=1,2
CALL MPI_TYPE_FREE(Elem_Type(i), IError)
END DO
! (3) Send the array
CALL MPI_SEND(Structs(1)%N, 1, TwoElem_Type, ...)
请注意,尽管构造 MPI 数据类型是一项相对便宜的操作,但您不应使用上述过程发送例如结构化类型的 1000000 个实例。此外,MPI 数据类型描述符存在于库管理的内存中,及时释放不再需要的数据类型很重要。