Results and non-blocking operations¶
Buffers passed as rvalues are moved into an operation and handed back by value; buffers passed as lvalues are
borrowed and handed back by reference. Blocking operations with two buffers return them in a result;
non-blocking operations return an iresult, which owns the request and keeps owned buffers out of reach until the
operation has completed. See Non-blocking operations.
Blocking results¶
-
template<typename SBuf, typename RBuf>
struct result¶ The send and receive buffer of a blocking operation with both, e.g.
sendrecvoralltoallv.A buffer passed as an lvalue is borrowed: the member is a reference to it. A buffer passed as an rvalue was moved into the operation and is handed back here by value. Unpack it with a structured binding:
auto [_, recv] = kamping::v2::allgatherv(local, kamping::v2::auto_recv_v<int>(), comm);
Defined in header
<kamping/v2/result.hpp>
Non-blocking results¶
-
template<typename Buf>
class iresult<Buf>¶ The pending result of a non-blocking operation with one buffer, e.g.
isendorirecv.A buffer passed as an rvalue is moved into the
iresult, which owns it until the operation has completed: it is only accessible throughwait()or a successfultest(), so it cannot be touched while MPI may still use it. A buffer passed as an lvalue is borrowed; you must not access it before completion.auto pending = kamping::v2::irecv(std::vector<int>{} | kamping::v2::views::resize, source, comm); // ... other work ... std::vector<int> data = pending.wait().underlying();
An
iresultis move-only, and moving it keeps the buffer in place. It must be completed withwait()or a successfultest(): destroying or assigning over aniresultwhose operation is still active prints a diagnostic and callsstd::terminate(), instead of releasing a buffer that MPI may still be using.Defined in header
<kamping/v2/iresult.hpp>-
iresult &operator=(iresult &&other) noexcept¶
Takes over
other’s operation and buffer. Terminates if this iresult’s operation is still active.
-
template<convertible_to_mpi_handle_ptr<MPI_Status> Status = MPI_Status*>
decltype(auto) wait(Status &&status = MPI_STATUS_IGNORE)¶ Blocks until the operation completes, then returns the buffer: an owned buffer by value (the iresult is left empty), a borrowed buffer by reference.
- Parameters:
status– Optional: filled with the status of the operation. Defaults toMPI_STATUS_IGNORE.
-
template<convertible_to_mpi_handle_ptr<MPI_Status> Status = MPI_Status*>
auto test(Status &&status = MPI_STATUS_IGNORE)¶ Checks whether the operation has completed, without blocking.
For a borrowed buffer, returns whether the operation has completed. For an owned buffer, returns a
std::optionalholding the buffer if it has (the iresult is then left empty), andstd::nulloptif it is still active, in which case you can test again orwait().- Parameters:
status– Optional: filled with the status of the operation if it has completed. Defaults toMPI_STATUS_IGNORE.
-
iresult &operator=(iresult &&other) noexcept¶
-
template<typename SBuf, typename RBuf>
class iresult<SBuf, RBuf>¶ The pending result of a non-blocking operation with a send and a receive buffer, e.g.
isendrecv.Like the one-buffer
iresult: buffers passed as rvalues are owned until completion, buffers passed as lvalues are borrowed, and the operation must be completed withwait()or a successfultest(). Both return the buffers as aresult.Defined in header
<kamping/v2/iresult.hpp>-
iresult &operator=(iresult &&other) noexcept
Takes over
other’s operation and buffers. Terminates if this iresult’s operation is still active.
-
template<convertible_to_mpi_handle_ptr<MPI_Status> Status = MPI_Status*>
result<SBuf, RBuf> wait(Status &&status = MPI_STATUS_IGNORE)¶ Blocks until the operation completes, then returns both buffers: owned buffers by value (the iresult is left empty), borrowed buffers by reference.
- Parameters:
status– Optional: filled with the status of the operation. Defaults toMPI_STATUS_IGNORE.
-
template<convertible_to_mpi_handle_ptr<MPI_Status> Status = MPI_Status*>
std::optional<result<SBuf, RBuf>> test(Status &&status = MPI_STATUS_IGNORE)¶ Checks whether the operation has completed, without blocking.
- Parameters:
status– Optional: filled with the status of the operation if it has completed. Defaults toMPI_STATUS_IGNORE.
-
iresult &operator=(iresult &&other) noexcept
Requests¶
-
class request¶
Owning, move-only wrapper around an MPI_Request.
Satisfies convertible_to_mpi_handle_ptr<MPI_Request>, so it can be passed directly to any non-blocking operation as its request argument:
kamping::v2::request r; kamping::v2::isend(r, buf, dest, comm); r.wait();
The request must be completed explicitly — with
wait(), a successfultest(), or the free completion functions — or handed off withrelease(); the library never completes a request implicitly. Destroying or move-assigning over a request that is still active is a hard error: it prints a diagnostic and calls std::terminate(), also during exception unwinding. Unlike iresult, request does not own the buffer: the caller must keep it alive until the request completes.Ownership can be handed back to raw MPI code with
release(), and moved into or out of arequest_vectorwithrequest_vector::push_back(request&&)/request_vector::extract().Defined in header
<kamping/v2/request.hpp>-
request() noexcept = default¶
(1) -
explicit request(MPI_Request req) noexcept¶
(2) (1) Constructs a null request (MPI_REQUEST_NULL).
(2) Takes over responsibility for completing
req. The caller must not completereqitself afterwards.
-
request &operator=(request &&other) noexcept¶
Takes over
other’s request. Terminates if this still holds an active request.
-
~request()¶
Terminates if the request is still active (see class documentation).
-
bool is_null() const noexcept¶
- Returns:
trueif this holds MPI_REQUEST_NULL (never started, completed, or released).
-
MPI_Request release() noexcept¶
Gives up responsibility for the request and returns it; this becomes MPI_REQUEST_NULL.
-
operator request_view() noexcept¶
- Returns:
A non-owning view of this request.
-
template<convertible_to_mpi_handle_ptr<MPI_Status> Status = MPI_Status*>
void wait(Status &&status = MPI_STATUS_IGNORE)¶ Shorthand for
wait(*this, status).
-
template<convertible_to_mpi_handle_ptr<MPI_Status> Status = MPI_Status*>
bool test(Status &&status = MPI_STATUS_IGNORE)¶ Shorthand for
test(*this, status).
-
request() noexcept = default¶
-
class request_view¶
Non-owning wrapper around an MPI_Request*.
Satisfies convertible_to_mpi_handle_ptr<MPI_Request> so it can be passed to any non-blocking operation as its request argument. Does not complete or free the request on destruction — use request or iresult for RAII.
wait() and test() are shorthands for the free functions
wait()andtest()and follow the same semantics as iresult: wait() blocks until the operation completes; test() polls and returns true when done. Both accept an optional status out-parameter via convertible_to_mpi_handle_ptr<MPI_Status> (raw MPI_Status*,status_view, or omitted to use MPI_STATUS_IGNORE). Sincerequest_viewis non-owning, wait() returns void — the buffer is the caller’s responsibility.Defined in header
<kamping/v2/request.hpp>
-
class request_vector¶
Owning, growable array of MPI requests that mirrors
std::vector, but whose element access yieldsrequest_views instead of rawMPI_Requests.The requests are stored contiguously, so the whole array can be passed to the multiple-completion functions (
waitall,testany,waitsome, …) without copying; it exposes them viampi_handle_range()rather thandata(), since its elements as a range arerequest_views, notMPI_Requests.Typical use is to hand a fresh slot straight to a non-blocking operation:
kamping::v2::request_vector requests; kamping::v2::isend(requests.emplace_back(), buf, dest, comm); kamping::v2::waitall(requests);
Ownership: move-only. Like
request, the vector never completes a request implicitly: every request must be completed explicitly (e.g.waitall(requests)) or handed off withrelease()/extract()before it is dropped. Dropping an active request prints a diagnostic and callsstd::terminate(). This applies to the destructor and move assignment, and equally to the modifiers that remove slots:clear(), shrinkingresize()andpop_back().Invalidation follows
std::vector: arequest_viewpoints into the internal storage, so it is invalidated by any reallocation (emplace_back/push_backbeyondcapacity(),reserve,resize) and byerase_null(). TheMPI_Requesthandles themselves are plain values and survive reallocation unchanged.There is no const element access: a
request_viewmust be able to complete (and thus write) its request.Defined in header
<kamping/v2/request.hpp>-
explicit request_vector(size_type n)¶
Constructs
nslots, eachMPI_REQUEST_NULL.
-
request_vector &operator=(request_vector &&other) noexcept¶
Takes over the requests of
other. Terminates if this still holds an active request.
-
~request_vector()¶
Terminates if any request is still active (see class documentation).
-
void reserve(size_type n)¶
Reserves storage for
nrequests. Invalidates all views if it reallocates.
-
void resize(size_type n)¶
Resizes to
nslots. New slots areMPI_REQUEST_NULL.Terminates if a dropped slot (index
>= n) still holds an active request; complete those first.
-
void clear()¶
Removes all slots. Terminates if any request is still active; complete them first (e.g.
waitall).
-
request_view emplace_back()¶
Appends a
MPI_REQUEST_NULLslot and returns a view of it, ready to be passed to a non-blocking operation as its request output parameter.
-
void push_back(MPI_Request req)¶
(1) -
void push_back(request &&req)¶
(2) (1) Appends the raw handle
req, taking over responsibility for completing it.The caller must not complete
reqitself afterwards: once the vector completes it, MPI frees it and any remaining copy of the handle is stale.(2) Moves the owning request
reqinto the vector;reqis left null.
-
MPI_Request release(size_type i) noexcept¶
Gives up responsibility for the request at index
iand returns it as a raw handle.The slot becomes
MPI_REQUEST_NULLbut is not removed, so other indices and views stay valid; remove empty slots later witherase_null(). The caller must complete the returned request. Precondition:i < size().
-
request extract(size_type i) noexcept¶
Moves the request at index
iout into an owningrequest.Like
release(i), the slot becomesMPI_REQUEST_NULLand is not removed. Precondition:i < size().
-
void pop_back()¶
Removes the last slot. Terminates if it still holds an active request. Precondition:
!empty().
-
size_type erase_null()¶
Removes all
MPI_REQUEST_NULLslots (completed or never started), keeping the order of the rest.Useful in polling loops after
testsome/waitsome. Inactive persistent requests are notMPI_REQUEST_NULLand are kept. Invalidates all views.- Returns:
The number of removed slots.
-
request_view operator[](size_type i) noexcept¶
- Returns:
A view of the request at index
i. Precondition:i < size().
-
explicit request_vector(size_type n)¶
Completion¶
The functions completing several requests take any writable contiguous range of MPI_Requests, such as a
request_vector or a std::vector<MPI_Request>, and of MPI_Statuses for the statuses:
-
template<typename T>
concept request_range¶ template<typename T> concept request_range = convertible_to_mpi_handle_range<T, MPI_Request> && std::ranges::sized_range<decltype(kamping::v2::handle_range(std::declval<T&>()))>
The request array of a multi-request call (
waitall,waitany,waitsome, …): a writable contiguous range ofMPI_Requestobtained through handle_range(). It must be sized, since its size is the request count.Defined in header
<mpi/arrays.hpp>
-
template<typename T, typename E>
concept output_array_of¶ template<typename T, typename E> concept output_array_of = (builtin_handle<E> && convertible_to_mpi_handle_range<T, E>) || (!builtin_handle<E> && output_range_of<T&, E>)
An output array of
E. Handle elements are obtained through handle_range(), so that types such asstatus_vectorcan expose their storage; other element types (e.g.intindices) must be a plain contiguous range. A sized array is checked to hold the required number of elements; an unsized one is trusted.Defined in header
<mpi/arrays.hpp>
-
template<typename T, typename E>
concept output_array_or_ignore_of¶ template<typename T, typename E> concept output_array_or_ignore_of = output_array_of<T, E> || output_array_sentinel_of<T, E>
An output array of
Ethat MPI allows to be ignored: anoutput_array_of<E>or a matching sentinel.Defined in header
<mpi/arrays.hpp>
-
template<convertible_to_mpi_handle_ptr<MPI_Request> Request, convertible_to_mpi_handle_ptr<MPI_Status> Status = MPI_Status*>
void wait(Request &&request, Status &&status = MPI_STATUS_IGNORE)¶ Blocks until the operation associated with
requestcompletes (MPI_Wait).On return,
requestis set toMPI_REQUEST_NULL(or marked inactive, for persistent requests). Waiting onMPI_REQUEST_NULLreturns immediately with an empty status.- Parameters:
request– Anything convertible to anMPI_Request*(rawMPI_Request,request_view, …).status– Optional status out-parameter; omit to useMPI_STATUS_IGNORE.
Defined in header
<kamping/v2/completion.hpp>
-
template<convertible_to_mpi_handle_ptr<MPI_Request> Request, convertible_to_mpi_handle_ptr<MPI_Status> Status = MPI_Status*>
bool test(Request &&request, Status &&status = MPI_STATUS_IGNORE)¶ Checks whether the operation associated with
requesthas completed (MPI_Test).If it has,
requestis set toMPI_REQUEST_NULL(or marked inactive, for persistent requests) andstatusis filled in. TestingMPI_REQUEST_NULLreturnstrue.- Parameters:
request– Anything convertible to anMPI_Request*(rawMPI_Request,request_view, …).status– Optional status out-parameter; omit to useMPI_STATUS_IGNORE.
- Returns:
trueif the operation has completed.
Defined in header
<kamping/v2/completion.hpp>
-
template<request_range Requests, output_array_or_ignore_of<MPI_Status> Statuses = statuses_ignore_t>
void waitall(Requests &&requests, Statuses &&statuses = statuses_ignore_t{})¶ Blocks until all operations in
requestscomplete (MPI_Waitall).On return, every request is set to
MPI_REQUEST_NULL(or marked inactive, for persistent requests).MPI_REQUEST_NULLentries are allowed and ignored.- Parameters:
requests– A writable contiguous range ofMPI_Request(seerequest_range).statuses– Optional: a writable contiguous range ofMPI_Statuswith at least as many entries asrequests;statuses[i]receives the status ofrequests[i]. Defaults tostatuses_ignore.
Defined in header
<kamping/v2/completion.hpp>
-
template<request_range Requests, output_array_or_ignore_of<MPI_Status> Statuses = statuses_ignore_t>
bool testall(Requests &&requests, Statuses &&statuses = statuses_ignore_t{})¶ Checks whether all operations in
requestshave completed (MPI_Testall).Either all requests complete and are set to
MPI_REQUEST_NULL, or none of them is modified.- Parameters:
requests– A writable contiguous range ofMPI_Request(seerequest_range).statuses– Optional: a writable contiguous range ofMPI_Statuswith at least as many entries asrequests; only written if this returnstrue. Defaults tostatuses_ignore.
- Returns:
trueif all operations have completed.
Defined in header
<kamping/v2/completion.hpp>
-
template<request_range Requests, convertible_to_mpi_handle_ptr<MPI_Status> Status = MPI_Status*>
std::optional<std::size_t> waitany(Requests &&requests, Status &&status = MPI_STATUS_IGNORE)¶ Blocks until any one operation in
requestscompletes (MPI_Waitany).The completed request is set to
MPI_REQUEST_NULL(or marked inactive, for persistent requests).- Parameters:
requests– A writable contiguous range ofMPI_Request(seerequest_range).status– Optional status out-parameter for the completed operation; omit to useMPI_STATUS_IGNORE.
- Returns:
The index of the completed request, or
std::nulloptifrequestscontains no active request (MPI_UNDEFINED).
Defined in header
<kamping/v2/completion.hpp>
-
template<request_range Requests, convertible_to_mpi_handle_ptr<MPI_Status> Status = MPI_Status*>
testany_result testany(Requests &&requests, Status &&status = MPI_STATUS_IGNORE)¶ Checks whether any one operation in
requestshas completed (MPI_Testany).- Parameters:
requests– A writable contiguous range ofMPI_Request(seerequest_range).status– Optional status out-parameter for the completed operation; omit to useMPI_STATUS_IGNORE.
- Returns:
A
testany_result: pending, the completed index, or no active request.
Defined in header
<kamping/v2/completion.hpp>
-
class testany_result¶
Result of
testany: an optional-like index with an additional pending state.Exactly one of three states holds:
pending(): no operation has completed yet;waitanywould block.has_value(), index*r:requests[*r]completed and was set toMPI_REQUEST_NULL.neither:
requestscontains no active request (MPI_UNDEFINED).
There is deliberately no
operator bool:if (r)could plausibly mean either “not pending” or “has an index”, and guessing wrong in a polling loop spins forever. Callpending()orhas_value()explicitly.Defined in header
<kamping/v2/completion.hpp>-
testany_result(bool flag, int index) noexcept¶
Constructs from the
flagandindexoutputs ofMPI_Testany.
-
bool pending() const noexcept¶
- Returns:
trueif no operation has completed yet.
-
bool has_value() const noexcept¶
- Returns:
trueif an operation completed; its index is then available via*rorvalue().
-
std::size_t operator*() const noexcept¶
- Returns:
The index of the completed request. Precondition:
has_value().
-
std::size_t value() const¶
- Throws:
std::bad_optional_access– if!has_value().
- Returns:
The index of the completed request.
-
template<request_range Requests, output_array_of<int> Indices, output_array_or_ignore_of<MPI_Status> Statuses = statuses_ignore_t>
std::optional<std::size_t> waitsome(Requests &&requests, Indices &&indices, Statuses &&statuses = statuses_ignore_t{})¶ Blocks until at least one operation in
requestscompletes (MPI_Waitsome).Completed requests are set to
MPI_REQUEST_NULL(or marked inactive, for persistent requests).- Parameters:
requests– A writable contiguous range ofMPI_Request(seerequest_range).indices– A writable contiguous range ofintwith at least as many entries asrequests; the firstnentries receive the indices of the completed requests.statuses– Optional: a writable contiguous range ofMPI_Statuswith at least as many entries asrequests, written in completion order:statuses[k]belongs torequests[indices[k]], not torequests[k]. Defaults tostatuses_ignore.
- Returns:
The number
nof completed requests, orstd::nulloptifrequestscontains no active request (MPI_UNDEFINED).
Defined in header
<kamping/v2/completion.hpp>
-
template<request_range Requests, output_array_of<int> Indices, output_array_or_ignore_of<MPI_Status> Statuses = statuses_ignore_t>
std::optional<std::size_t> testsome(Requests &&requests, Indices &&indices, Statuses &&statuses = statuses_ignore_t{})¶ Checks which operations in
requestshave completed, without blocking (MPI_Testsome).Same contract as
waitsome, except that it returns0if no operation has completed yet.- Returns:
The number of completed requests (possibly
0), orstd::nulloptifrequestscontains no active request (MPI_UNDEFINED).
Defined in header
<kamping/v2/completion.hpp>
-
statuses_ignore_t statuses_ignore¶
The
statuses_ignore_tsentinel.Defined in header
<kamping/v2/sentinels.hpp>