2016-09-17 76 views
1

我正在使用irecv()函数接收boost::mpi消息。我有一个等待循环,在irecv返回的request对象上调用test(),如果请求完成,则执行某些操作。然而,试图找出发件人的排名,我得到一个异常:boost :: mpi's irecv()返回非初始化状态对象

boost::optional<T>::reference_type boost::optional<T>::get() [with T = boost::mpi::status; boost::optional<T>::reference_type = boost::mpi::status&]: Assertion `this->is_initialized()' failed. 

这里是我的代码片段:

mpi::request inc = world.irecv(mpi::any_source, MpiHandler::MPI_RESULT, pxl_results); 
do { 
    if(inc.test()) { 
     // fails here, as the optional<status> returned by inc.test() is not initialized. 
     world.send(inc.test().get().source(), MpiHandler::MPI_WORK, package); 
     ... 
    } 
} while(...); 

如果我检查inc.test().is_initialized(),我发现optional<status>确实未初始化。这里发生了什么,为什么我无法找到有关我的MPI发件人的任何信息?是否可能是mpi::any_sourceirecv搭配不好?


只需添加:典型地,MPI消息的发送者和标签可以从请求对象被发现像this answer概述。

回答

1

我很高兴你能解决它,但也许这将进一步解释它。

这个问题在req.test()成功调用后再次调用req.test()。在MPI - 完整的参考:第1卷,所述的MPI核心

请求目的是通过成功调用MPI_WAIT或MPI_TEST自动释放。

另外,从升压MPI文档:

可选<状态>试验(); 确定与此请求关联的通信是否已成功完成。如果是,则返回描述通信的状态对象。否则,返回一个空的可选<>表示通讯尚未完成。 请注意,一旦test()返回一个状态对象,请求就完成了,wait()不应该被调用。

因此,成功后一个boost::optional<mpi::status>if(req.test())回到req.test()的后续调用可能会返回一个空optional<>导致你的异常。

要看到这一点,我们首先在联答案创建乔纳森·德西的Hello World示例一个例子:

#include <boost/mpi.hpp> 
#include <iostream> 
#include <string> 
#include <boost/serialization/string.hpp> 
namespace mpi = boost::mpi; 

int main() 
{ 
    mpi::environment env; 
    mpi::communicator world; 

    if (world.rank() == 0) { 
    std::string msg, out_msg = "Hello from rank 0."; 
    world.send(1, 17, out_msg); 
    } else { 
    mpi::request req; 
    std::string rmsg; 

    req = world.irecv(mpi::any_source, mpi::any_tag, rmsg); 
    do { 
     if(req.test()) { 
     // fails here, as the optional<status> returned by inc.test() is not initialized. 
     std::cout << "From " << req.test().get().source() << std::endl; 
     std::cout << "Got " << rmsg << std::endl; 
     break; 
     } 
    } while(1); 
    } 

    return 0; 
} 

构建和运行这导致预期异常:

[ronin:~/Documents/CPP] aichao% mpirun --hostfile hostfile -np 2 ./test_mpi_request 
From Assertion failed: (this->is_initialized()), function get, file /Users/Shared/Tools/boost_1_53_0/boost/optional/optional.hpp, line 631. 

要解决此:

  1. 致电req.test()返回boost::optional<mpi::status>对象。
  2. 测试boost::optional对象查看req.test()是否成功返回,如果成功,请使用返回的mpi::status

代码:

#include <boost/mpi.hpp> 
#include <iostream> 
#include <string> 
#include <boost/serialization/string.hpp> 
namespace mpi = boost::mpi; 

int main() 
{ 
    mpi::environment env; 
    mpi::communicator world; 

    if (world.rank() == 0) { 
    std::string msg, out_msg = "Hello from rank 0."; 
    world.send(1, 17, out_msg); 
    } else { 
    mpi::request req; 
    std::string rmsg; 

    req = world.irecv(mpi::any_source, mpi::any_tag, rmsg); 
    do { 
     boost::optional<mpi::status> stat = req.test(); 
     if (stat) { 
     std::cout << "From " << stat->source() << std::endl; 
     std::cout << "Got " << rmsg << std::endl; 
     std::cout << "Tagged " << stat->tag() << std::endl; 
     break; 
     } 
    } while(1); 
    } 

    return 0; 
} 

现在,我们已经成功:

[ronin:~/Documents/CPP] aichao% mpirun --hostfile hostfile -np 2 ./test_mpi_request 
From 0 
Got Hello from rank 0. 
Tagged 17 
+0

正如我在答复中指出,这是问题。谢谢你的好评。 – janoliver

+0

这与MPI标准中定义的MPI请求的语义有明显的偏差,我认为它是boost :: mpi中的一个错误。一旦'MPI_Test'或'MPI_Wait'成功,它就释放请求并将请求句柄的内容重置为'MPI_REQUEST_NULL'。用空请求调用'MPI_Test'或'MPI_Wait'是一个明确定义的行为,标准规定了这种情况下状态对象的内容。 –

+0

@HristoIliev:我同意你的看法,但我不相信'boost :: mpi'的目标是完全保留MPI的语义。只要它的API和使用模式有充分的文档记载(你可以争辩说它不是),我不会认为这是一个错误,本身。 – aichao

0

我想通了:问题是我再次打电话test(),这显然无效的东西。它适用于

auto ret = inc.test(); 
if(ret) { 
    // use ret->source() 
}