交错式MPI Isend / Recv的安全保证

时间:2014-03-04 14:26:13

标签: c++ thread-safety mpi communication openmpi

related question中,我了解到,request = Isend(...); Recv(...); request.Wait(); 保证无法正常工作,因为Isendrequest.Wait()之前可能无法执行任何操作在Recv(...)处死锁(详见原始问题)。

但是如果在Isend() / Wait()之外的另一个线程上执行Recv呢?我现在对标准的安全保障并不直接感兴趣。这是因为如果调用适当的Init_thread方法并且返回正确的级别,则标准仅断言线程安全性。使用我的openMPI配置,情况并非如此。但是,我看不出某个实现实际上仅限制来自调用Init_thread的线程的调用的原因(需要对线程id进行实际比较)。我的理由是:如果我序列化所有发送和所有recvs,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();
}

代码说明:在每个处理器上执行两个线程。一个人尝试Isend向合作伙伴提供一些数据并等待这一切完成,另一个人从合作伙伴那里收到一些数据。

问题:我能否安全地假设大多数MPI实现都没有扼杀这段代码?

(免责声明:这段代码不是设计为异常安全或特别漂亮的。它仅用于演示目的)

1 个答案:

答案 0 :(得分:1)

  

问题:我能否安全地假设大多数MPI实现都没有扼杀这段代码?

实际上 - 是的,如果你添加同步(你的代码缺乏);在理论上 - 没有。虽然某些实现可能允许来自MPI_THREAD_SINGLE级别的不同线程的序列化调用(Open MPI就是这样 - 请参阅here),但MPI标准要求必须在MPI_THREAD_SERIALIZED级别。如果您希望软件可移植并且能够与其他MPI实现一起编译和运行,则不应该依赖某些特定的Open MPI行为。

也就是说,Open MPI可以配置为在构建库时支持多线程(MPI_THREAD_MULTIPLE)。默认情况下,出于性能原因,MT支持未启用。您可以使用ompi_info检查特定安装的状态:

$ ompi_info | grep MPI_THREAD_MULTIPLE
     Thread support: poxis (MPI_THREAD_MULTIPLE: no, progress: no)
                            ^^^^^^^^^^^^^^^^^^^^^^^

该特定版本不支持多线程,并且始终会在MPI_THREAD_SINGLE的{​​{1}}输出参数中返回provided