在一个相关问题中,我了解到执行request = Isend(...); Recv(...); request.Wait();不能保证工作,因为Isend在request.Wait()之前可能不会做任何事情,因此在Recv(...)上会出现死锁(详见原始问题)。
但是,如果Isend() / Wait()是在另一个线程上执行,而不是在Recv上执行呢?按照标准,我现在对安全保障没有直接的兴趣。这是因为如果调用了适当的Init_thread方法并返回正确的级别,则标准只断言线程安全性。就我的openMPI配置而言,情况并非如此。但是,我看不出为什么实现实际上只限制来自名为Init_thread的线程的调用(需要对线程id进行实际比较)。我的理由是:如果我序列化所有发送和所有recv,mpi永远不会注意到我使用的是多个线程。
所以我的简化代码是:
#include <cassert>
#include <thread>
#include "mpi.h"
void send(int rank, int& item)
{
MPI::Request request = MPI::COMM_WORLD.Isend(&item, sizeof(int), MPI::BYTE, rank, 0);
request.Wait();
}
void recv(int rank, int& item)
{
MPI::COMM_WORLD.Recv(&item, sizeof(int), MPI::BYTE, rank, 0);
}
int main()
{
MPI::Init();
int ns[] = {-1, -1};
int rank = MPI::COMM_WORLD.Get_rank();
ns[rank] = rank;
auto t_0 = std::thread(send, 1 - rank, std::ref(ns[rank])); // send rank to partner (i.e. 1 - rank)
auto t_1 = std::thread(recv, 1 - rank, std::ref(ns[1 - rank])); // receive partner rank from partner
t_0.join();
t_1.join();
assert( ns[0] == 0 );
assert( ns[1] == 1 );
MPI::Finalize();
}代码说明:在每个处理器上执行两个线程。一个尝试将一些数据发送给合作伙伴并等待它完成,另一个则从合作伙伴那里接收一些数据。
问:我能安全地假设MPI的大多数实现不会被这段代码阻塞吗?
(免责声明:这段代码不是设计为异常安全或特别漂亮。只供演示之用)
发布于 2014-03-04 16:08:29
问:我能安全地假设MPI的大多数实现不会被这段代码阻塞吗?
在实践中-是的,如果您添加同步(这是您的代码缺乏);在理论上-否。虽然有些实现可能允许来自MPI_THREAD_SINGLE级别的不同线程的序列化调用( Open就是这样的调用--参见这里),但是MPI标准要求库必须在MPI_THREAD_SERIALIZED级别初始化。如果您希望您的软件是可移植的,并且能够与其他MPI实现一起正确编译和运行,则不应该依赖某些特定的Open行为。
也就是说,在构建库时,可以将Open配置为支持多线程(MPI_THREAD_MULTIPLE)。默认情况是,出于性能原因,不启用MT支持。您可以使用ompi_info检查特定安装的状态。
$ ompi_info | grep MPI_THREAD_MULTIPLE
Thread support: poxis (MPI_THREAD_MULTIPLE: no, progress: no)
^^^^^^^^^^^^^^^^^^^^^^^这个特定的构建不支持多线程,并且总是在MPI_THREAD_SINGLE的provided输出参数中返回MPI_Init_thread。
https://stackoverflow.com/questions/22174639
复制相似问题