Non-blocking send and receive#
Demonstrates non-blocking send and receive of standard data types and vectors of standard data types and different waiting methods.
#include <cstdlib>
#include <iostream>
#include <array>
#include <vector>
#include <numeric>
#include <mpl/mpl.hpp>
template<typename I>
void print_range(const char *const str, I i_1, I i_2) {
std::cout << str;
while (i_1 != i_2) {
std::cout << (*i_1);
++i_1;
std::cout << ((i_1 != i_2) ? ' ' : '\n');
}
}
int main() {
const mpl::communicator &comm_world{mpl::environment::comm_world()};
// run the program with two or more processes
if (comm_world.size() < 2)
return EXIT_FAILURE;
const int n{12};
std::vector<int> v_1(n), v_2(n), v_3(n), v_4(n);
mpl::contiguous_layout<int> l(n);
// process 0 sends
if (comm_world.rank() == 0) {
// see MPI Standard for the semantics of standard send, buffered send,
// synchronous send and ready send
double x{1.23456};
mpl::irequest r(comm_world.isend(x, 1)); // send x to rank 1 via standard send
r.wait(); // wait until send has finished
++x;
{
// create a buffer for buffered send,
// memory will be freed on leaving the scope
const int size{comm_world.bsend_size<decltype(x)>()};
mpl::bsend_buffer buff(size);
r = comm_world.ibsend(x, 1); // send x to rank 1 via buffered send
r.wait(); // wait until send has finished
}
++x;
r = comm_world.issend(x, 1); // send x to rank 1 via synchronous send
r.wait(); // wait until send has finished
++x;
r = comm_world.irsend(x, 1); // send x to rank 1 via ready send
r.wait(); // wait until send has finished
std::iota(v_1.begin(), v_1.end(), 0);
std::iota(v_2.begin(), v_2.end(), 1);
std::iota(v_3.begin(), v_3.end(), 2);
std::iota(v_4.begin(), v_4.end(), 3);
{
// create a buffer for buffered send,
// memory will be freed on leaving the scope
const int size{comm_world.bsend_size(l)};
mpl::bsend_buffer buff(size);
mpl::irequest_pool r;
r.push(comm_world.isend(v_1.data(), l, 1)); // send x to rank 1 via standard send
r.push(comm_world.ibsend(v_2.data(), l, 1)); // send x to rank 1 via buffered send
r.push(comm_world.issend(v_3.data(), l, 1)); // send x to rank 1 via synchronous send
r.push(comm_world.irsend(v_4.data(), l, 1)); // send x to rank 1 via ready send
r.waitall(); // wait until all sends have finished
}
{
mpl::irequest_pool r;
const int size{comm_world.bsend_size(l)};
mpl::bsend_buffer buff(size);
r.push(comm_world.isend(v_1.data(), l, 1)); // send v1 to rank 1 via standard send
r.push(comm_world.ibsend(v_2.data(), l, 1)); // send v2 to rank 1 via buffered send
r.push(comm_world.issend(v_3.data(), l, 1)); // send v3 to rank 1 via synchronous send
r.push(comm_world.irsend(v_4.data(), l, 1)); // send v4 to rank 1 via ready send
while (true) {
auto finished{r.waitsome()}; // wait until one or more sends have finished
if (finished.first ==
mpl::test_result::no_active_requests) // there have been no pending sends
break;
// print indices of finished sends
std::cout << "send finished : ";
std::for_each(finished.second.begin(), finished.second.end(),
[](mpl::irequest_pool::size_type j) { std::cout << j << ' '; });
std::cout << "\n";
}
}
}
// process 1 receives
if (comm_world.rank() == 1) {
double x;
mpl::irequest r(comm_world.irecv(x, 0)); // receive x from rank 0
r.wait(); // wait until receive has finished
std::cout << "x = " << x << '\n';
r = comm_world.irecv(x, 0); // receive x from rank 0
r.wait(); // wait until receive has finished
std::cout << "x = " << x << '\n';
r = comm_world.irecv(x, 0); // receive x from rank 0
r.wait(); // wait until receive has finished
std::cout << "x = " << x << '\n';
r = comm_world.irecv(x, 0); // receive x from rank 0
r.wait(); // wait until receive has finished
std::cout << "x = " << x << '\n';
{
mpl::irequest_pool r;
r.push(comm_world.irecv(v_1.data(), l, 0)); // receive v1 from rank 0
r.push(comm_world.irecv(v_2.data(), l, 0)); // receive v2 from rank 0
r.push(comm_world.irecv(v_3.data(), l, 0)); // receive v3 from rank 0
r.push(comm_world.irecv(v_4.data(), l, 0)); // receive v4 from rank 0
r.waitall(); // wait until all receives have finished
print_range("v = ", v_1.begin(), v_1.end());
print_range("v = ", v_2.begin(), v_2.end());
print_range("v = ", v_3.begin(), v_3.end());
print_range("v = ", v_4.begin(), v_4.end());
}
{
mpl::irequest_pool r;
r.push(comm_world.irecv(v_1.data(), l, 0)); // receive v1 from rank 0
r.push(comm_world.irecv(v_2.data(), l, 0)); // receive v2 from rank 0
r.push(comm_world.irecv(v_3.data(), l, 0)); // receive v3 from rank 0
r.push(comm_world.irecv(v_4.data(), l, 0)); // receive v4 from rank 0
while (true) {
auto finished{r.waitsome()}; // wait until one or more receives have finished
if (finished.first ==
mpl::test_result::no_active_requests) // there have been no pending receives
break;
// print indices of finished receives
std::cout << "recv finished : ";
std::for_each(finished.second.begin(), finished.second.end(),
[](mpl::irequest_pool::size_type j) { std::cout << j << ' '; });
std::cout << '\n';
}
print_range("v = ", v_1.begin(), v_1.end());
print_range("v = ", v_2.begin(), v_2.end());
print_range("v = ", v_3.begin(), v_3.end());
print_range("v = ", v_4.begin(), v_4.end());
}
}
return EXIT_SUCCESS;
}