我正在用C ++编写一个用于MPI的光包装器。为了使事情更容易,我有一些函数返回一个MPI_Request
对象而不是一个作为指针。代码在我的计算机上工作正常,但我担心它可能会导致MPI的不同实现出现问题。
下面是一些示例代码:
template<class T> MPI_Request ireceive(T* data, int count, int source, int tag)
{
MPI_Request request;
MPI_Irecv(data, get_mpi_type<T>::mul * count, get_mpi_type<T>::type(), source, tag, MPI_COMM_WORLD, &request);
return request;
}
template<class T> MPI_Request ireceive(std::vector<T>& dest, int source, int tag)
{
MPI_Status status = probe(source, tag);
int size = get_msg_size<T>(status);
dest.clear();
dest.resize(size);
return ireceive(&dest[0], size, source, tag, status);
}
MPI_Status wait(MPI_Request& request)
{
MPI_Status status;
MPI_Wait(&request, &status);
return status;
}
MPI_Status test(MPI_Request& request, int& flag)
{
MPI_Status status;
MPI_Test(&request, &flag, &status);
return status;
}
前两个函数直接返回一个MPI_Request对象,后两个函数返回一个MPI_Status对象。我担心,在另一个MPI实现中,这些函数可能会导致未定义的行为。
按值返回MPI_Request和MPI_Status对象是否危险?
答案 0 :(得分:2)
按值返回MPI_Request和MPI_Status对象是否危险?
可能会导致错误,如answer中所述。
会影响表现吗?
这些结构不应该大到足以降低性能,但一般来说,当通过引用传递是一种选择时,应该遵循它。
答案 1 :(得分:2)
MPI_Status
结构基本上是一个整数数组,用于报告特定通信的结果,无论是点对点接收还是非阻塞操作。复制此结构并不危险,您可以使用作业或memcpy
来完成。复制它的性能损失应该不是问题,因为这些元素的典型大小约为20字节(MPI 3.1)。
另一方面,MPI_Request
并非无足轻重。我还在C ++中为一个项目制作了一些MPI包装器(因为C ++ API已被弃用,并且在各个实现中不一致)。 MPI_Request
结构基本上是句柄(将其看作指针),用于检查操作的完成状态。如果释放句柄(因为非阻塞操作已完成,或者您调用了MPI_Request_free
或MPI_Cancel
,则该对象不再有效,并且MPI_Request
句柄设置为{ {1}}。
根据我的经验,MPI_REQUEST_NULL
包装类最好是不可复制的。您仍然可以使用引用或指针共享它们。这样可以节省一些调试时间。
参见MPI标准文件3.1,第3.7节“非阻塞通信”
如果请求标识的操作完成,则对
MPI_Request
的调用将返回MPI_TEST
。在这种情况下,状态对象被设置为包含关于已完成操作的信息。如果请求是活动持久请求,则将其标记为非活动。 取消分配任何其他类型的请求,请求句柄设置为flag = true
。 [...]允许一个使用null或inactive请求参数调用
MPI_REQUEST_NULL
。在这种情况下,操作将返回MPI_TEST
并为空状态。
注意:null或非活动请求不是无效的请求句柄,例如,它是释放flag = true
并仅将其中一个副本设置为MPI_Request
的结果。