Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/156.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 交叉MPI Isend/Recv的安全保证_C++_Thread Safety_Mpi_Communication_Openmpi - Fatal编程技术网

C++ 交叉MPI Isend/Recv的安全保证

C++ 交叉MPI Isend/Recv的安全保证,c++,thread-safety,mpi,communication,openmpi,C++,Thread Safety,Mpi,Communication,Openmpi,在一次实验中,我了解到执行request=Isend(…);Recv(…);request.Wait()不保证工作,因为在请求之前,Isend可能不会执行任何操作。Wait(),因此在Recv(…)处死锁(有关详细信息,请参阅原始问题) 但是如果在Recv之外的另一个线程上执行Isend()/Wait(),该怎么办?我现在对标准中的安全保证没有直接的兴趣。这是因为,如果调用适当的Init_thread方法并返回正确的级别,则标准仅断言线程安全。在我的openMPI配置中,情况并非如此。但是,我看

在一次实验中,我了解到执行
request=Isend(…);Recv(…);request.Wait()
不保证工作,因为在
请求之前,
Isend
可能不会执行任何操作。Wait()
,因此在
Recv(…)
处死锁(有关详细信息,请参阅原始问题)

但是如果在
Recv
之外的另一个线程上执行
Isend()/Wait()
,该怎么办?我现在对标准中的安全保证没有直接的兴趣。这是因为,如果调用适当的
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.h”
无效发送(整数排名、整数和项目)
{
MPI::Request Request=MPI::COMM_WORLD.Isend(&item,sizeof(int),MPI::BYTE,rank,0);
request.Wait();
}
无效记录(整数秩、整数和项目)
{
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[秩]=秩;
auto t_0=std::thread(send,1-rank,std::ref(ns[rank]);//将秩发送给伙伴(即1-rank)
auto t_1=std::thread(recv,1-rank,std::ref(ns[1-rank]);//从合作伙伴接收合作伙伴级别
t_0.join();
t_1.连接();
断言(ns[0]==0);
断言(ns[1]==1);
MPI::Finalize();
}
代码说明:每个处理器上执行两个线程。一个尝试向合作伙伴发送一些数据,并等待完成,另一个则从合作伙伴接收一些数据

问题:我可以安全地假设大多数MPI实现不会被这段代码阻塞吗

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

问题:我可以安全地假设大多数MPI实现不会被这段代码阻塞吗

实际上-是的,如果您添加了同步(您的代码缺少同步);理论上-否。虽然有些实现可能允许在
MPI\u THREAD\u SINGLE
级别上从不同线程进行序列化调用(Open MPI就是这样一种调用-请参阅),但MPI标准要求库必须在
MPI\u THREAD\u SERIALIZED
级别进行初始化。如果您希望您的软件是可移植的,并且能够使用其他MPI实现正确编译和运行,那么您不应该依赖某些特定的开放MPI行为

也就是说,可以将OpenMPI配置为在构建库时支持多线程(
MPI\u THREAD\u MULTIPLE
)。默认情况下,出于性能原因,不会启用MT支持。您可以使用
ompi\u info
检查特定安装的状态:

$ompi_info | grep MPI_线程|多个
线程支持:poxis(MPI\u线程\u倍数:否,进度:否)
^^^^^^^^^^^^^^^^^^^^^^^

该特定构建不支持多线程,并且在
MPI\u Init\u THREAD
提供的
输出参数中总是返回
MPI\u THREAD\u SINGLE

您在相关问题中了解到的内容是错误的。@hristoilev感谢您在那里发布答案:)这是一个非常好的消息(嗯,部分原因是。这意味着在其他地方有一个bug-。),因为我不必完全抛弃我的概念。我可以问一下代码的哪些部分需要同步?用相同的互斥锁包装
Isend
Recv
就足够了吗?所有MPI调用都必须与关键部分同步,无论它是如何实现的。谢谢,我想我现在看到了解决问题的方法:)请注意,您的问题存在一个单行解决方案:
MPI\u Allgather(MPI\u IN\u PLACE,0,MPI\u DATATYPE\u NULL,ns,1,MPI\u INT,MPI\u COMM\u WORLD)(无论C++等效)。这是一个相当简化的示例代码。在我的实际应用程序中,我需要收集主节点上的结果(相当随机)并将作业分发给节点。我可以请你看一下下面的代码并告诉我它是否安全吗?