2016-09-17 89 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() 
}