janoliver janoliver - 2 months ago 18
C++ Question

boost::mpi's irecv() returns non-initialized status objects

Im am receiving

boost::mpi
messages using the
irecv()
function. I have a waiting loop, that calls
test()
on the
request
object returned by
irecv
and, if the request finished, does something. However, trying to figure out the sender's rank, I get an exception:

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.


Here is my code snippet:

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(...);


If I check for
inc.test().is_initialized()
, I find that the
optional<status>
is indeed uninitialized. What is happening here, and why can I not find out anything about my MPI sender? Is it possibly the
mpi::any_source
that doesn't play well with
irecv
?




Just to add: Typically, the sender and tag of an MPI message can be found out from the request object like outlined in this answer.

Answer

I'm glad you worked it out, but maybe this will explain it further.

The issue is calling req.test() again after a successful call to req.test(). In MPI - The Complete Reference: Volume 1, The MPI Core:

A request object is deallocated automatically by a successful call to MPI_WAIT or MPI_TEST.

Also, from the boost mpi documentation:

optional< status > test(); Determine whether the communication associated with this request has completed successfully. If so, returns the status object describing the communication. Otherwise, returns an empty optional<> to indicate that the communication has not completed yet. Note that once test() returns a status object, the request has completed and wait() should not be called.

Therefore, after if(req.test()) returns successfully a boost::optional<mpi::status> a subsequent call to req.test() will likely return an empty optional<> leading to your exception.

To see this we first create an example from Jonathan Dursi's hello world example in the linked answer:

#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;
}

Building and running this leads to the exception as expected:

[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.

To fix this:

  1. Call req.test() to return a boost::optional<mpi::status> object.
  2. Test that boost::optional object to see if req.test() returned successfully and if successful, use the returned mpi::status.

The code:

#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;
}

Now, we have success:

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