API reference¶
pika follows semver. pika is currently at a 0.X version which means that minor versions may break the API. pika gives no guarantees about ABI stability. The ABI may change even in patch versions.
The API reference is a work in progress. While the reference is being expanded, the
More resources section contains useful links to high level overviews and low
level API descriptions of std::execution
.
The following headers are part of the public API. Any other headers are internal implementation details.
These headers are part of the public API, but are currently undocumented.
pika/async_rw_mutex.hpp
pika/barrier.hpp
pika/condition_variable.hpp
pika/cuda.hpp
pika/latch.hpp
pika/mpi.hpp
pika/mutex.hpp
pika/runtime.hpp
pika/semaphore.hpp
pika/thread.hpp
All functionality in a namespace containing detail
and all macros prefixed with PIKA_DETAIL
are implementation details and may change without warning at any time. All functionality in a
namespace containing experimental
may change without warning at any time. However, the intention
is to stabilize those APIs over time.
pika/init.hpp
¶
The pika/init.hpp
header provides functionality to manage the pika runtime.
#include <pika/execution.hpp>
#include <pika/init.hpp>
#include <fmt/printf.h>
#include <utility>
int main(int argc, char* argv[])
{
namespace ex = pika::execution::experimental;
namespace tt = pika::this_thread::experimental;
pika::start(argc, argv);
// The pika runtime is now active and we can schedule work on the default
// thread pool
auto s = ex::schedule(ex::thread_pool_scheduler{}) |
ex::then([]() { fmt::print("Hello from the pika runtime\n"); });
tt::sync_wait(std::move(s));
pika::finalize();
pika::stop();
return 0;
}
-
void pika::start(int argc, char const *const *argv, init_params const ¶ms = init_params())¶
Start the runtime.
No task is created on the runtime.
-
int pika::stop()¶
Stop the runtime.
Waits until pika::finalize() has been called and there is no more activity on the runtime. See pika::wait(). The runtime can be started again after calling pika::stop(). Must be called from outside the runtime.
- Returns:¶
the return value of the callable passed to pika::start(int, char const* const*,init_params const&)”, if any. If none was passed, returns 0.
- Pre:¶
the runtime is initialized
- Pre:¶
the calling thread is not a pika task
- Post:¶
the runtime is not initialized
-
void pika::finalize()¶
Signal the runtime that it may be stopped.
Until pika::finalize() has been called, pika::stop() will not return. This function exists to distinguish between the runtime being idle but still expecting work to be scheduled on it and the runtime being idle and ready to be shutdown. Unlike pika::stop(), pika::finalize() can be called from within or outside the runtime.
- Pre:¶
the runtime is initialized
-
void pika::wait()¶
Wait for the runtime to be idle.
Waits until the runtime is idle. This includes tasks scheduled on the thread pools as well as non-tasks such as CUDA kernels submitted through pika facilities. Can be called from within the runtime, in which case the calling task is ignored when determining idleness.
-
void pika::resume()¶
Resume the runtime.
Resumes the runtime by waking all worker threads on all thread pools.
-
void pika::suspend()¶
Suspend the runtime.
Waits until the runtime is idle and suspends worker threads on all thread pools. Work can be scheduled on the runtime even when it is suspended, but no progress will be made.
-
bool pika::is_runtime_initialized() noexcept¶
Returns true when the runtime is initialized, false otherwise.
Returns true between calls of pika::start(int, char const* const*, init_params const&) and pika::stop(), otherwise false.
Added in version 0.22.0.
-
struct init_params¶
pika/execution.hpp
¶
The pika/execution.hpp
header provides functionality related to std::execution
.
std::execution
functionality, including extensions provided by pika, is defined in the
pika::execution::experimental
namespace. When the CMake option PIKA_WITH_STDEXEC
is enabled,
pika pulls the stdexec
namespace into pika::execution::experimental
.
See Relation to std::execution and stdexec and More resources for more details on how pika relates
to std::execution
and for more resources on learning about std::execution
. Documentation for
sender functionality added to the C++ standard in the above resources apply to both pika’s and
stdexec’s implementations of them.
Documented below are sender adaptors not available in stdexec or not proposed for standardization.
All sender adaptors are customization point objects (CPOs).
-
constexpr drop_value_t pika::execution::experimental::drop_value = {}¶
Ignores all values sent by the predecessor sender, sending none itself.
Sender adaptor that takes any sender and returns a new sender that sends no values.
Added in version 0.6.0.
#include <pika/execution.hpp>
#include <pika/init.hpp>
#include <fmt/printf.h>
#include <tuple>
#include <utility>
struct custom_type
{
};
int main(int argc, char* argv[])
{
namespace ex = pika::execution::experimental;
namespace tt = pika::this_thread::experimental;
pika::start(argc, argv);
ex::thread_pool_scheduler sched{};
auto s = ex::just(42, custom_type{}, std::tuple("hello")) |
ex::drop_value() |
// No matter what is sent to drop_value, it won't be sent from
// drop_value
ex::then([] { fmt::print("I got nothing...\n"); });
tt::sync_wait(std::move(s));
pika::finalize();
pika::stop();
return 0;
}
-
constexpr drop_operation_state_t pika::execution::experimental::drop_operation_state = {}¶
Releases the operation state of the adaptor before signaling a connected receiver.
Sender adaptor that takes any sender and returns a sender. Values received as references from the predecessor sender will be copied before being passed on to successor senders. Other values are passed on unchanged.
The operation state of previous senders can hold on to allocated memory or values longer than necessary which can prevent other algorithms from using those resources.
drop_operation_state
can be used to explicitly release the operation state, and thus associated resources, of previous senders.
Added in version 0.19.0.
#include <pika/execution.hpp>
#include <pika/init.hpp>
#include <cassert>
#include <memory>
#include <utility>
int main(int argc, char* argv[])
{
namespace ex = pika::execution::experimental;
namespace tt = pika::this_thread::experimental;
pika::start(argc, argv);
ex::thread_pool_scheduler sched{};
auto sp = std::make_shared<int>(42);
std::weak_ptr<int> sp_weak = sp;
auto s = ex::just(std::move(sp)) |
ex::then([&](auto&&) { assert(sp_weak.use_count() == 1); }) |
// Even though the shared_ptr is no longer in use, it may be kept alive
// by the operation state
ex::then([&]() {
assert(sp_weak.use_count() == 1);
return 42;
}) |
ex::drop_operation_state() |
// Once drop_operation_state has been used, the shared_ptr is guaranteed
// to be released. Values are passed through the adaptor.
ex::then([&]([[maybe_unused]] int x) {
assert(sp_weak.use_count() == 0);
assert(x == 42);
});
tt::sync_wait(std::move(s));
pika::finalize();
pika::stop();
return 0;
}
-
constexpr require_started_t pika::execution::experimental::require_started = {}¶
Diagnose if a sender has not been started and terminates on destruction. It forwards the values of the predecessor sender.
Sender adaptor that takes any sender and returns a new sender that sends the same values as the predecessor sender.
The destructor terminates if the sender has not been connected or if the operation state has not been started. The operation state of a
require_started
sender is allowed to not be started if it has been explicitly requested with thediscard
member function.
Added in version 0.21.0.
#include <pika/execution.hpp>
#include <pika/init.hpp>
#include <fmt/printf.h>
#include <cassert>
#include <cstdlib>
#include <exception>
#include <utility>
int main(int argc, char* argv[])
{
namespace ex = pika::execution::experimental;
namespace tt = pika::this_thread::experimental;
pika::start(argc, argv);
ex::thread_pool_scheduler sched{};
{
// require_started forwards values received from the predecessor sender
auto s = ex::just(42) | ex::require_started() |
ex::then([]([[maybe_unused]] auto&& i) { assert(i == 42); });
tt::sync_wait(std::move(s));
}
{
// The termination is ignored with discard, the sender is from the
// user's perspective rightfully not used
auto s = ex::just() | ex::require_started();
s.discard();
}
{
// The require_started sender terminates on destruction if it has not
// been used
auto s = ex::just() | ex::require_started();
}
assert(false);
pika::finalize();
pika::stop();
return 0;
}
-
constexpr split_tuple_t pika::execution::experimental::split_tuple = {}¶
Splits a sender of a tuple into a tuple of senders.
Sender adaptor that takes a sender that sends a single, non-empty, tuple and returns a new tuple of the same size as the one sent by the input sender which contains one sender for each element in the input sender tuple. Each output sender signals completion whenever the input sender would have signalled completion. The predecessor sender must complete with exactly one tuple of at least one type.
Added in version 0.12.0.
#include <pika/execution.hpp>
#include <pika/init.hpp>
#include <fmt/printf.h>
#include <chrono>
#include <thread>
#include <tuple>
#include <utility>
int main(int argc, char* argv[])
{
namespace ex = pika::execution::experimental;
namespace tt = pika::this_thread::experimental;
pika::start(argc, argv);
ex::thread_pool_scheduler sched{};
// split_tuple can be used to process the result and its square through
// senders, without having to pass both around together
auto [snd, snd_squared] = ex::schedule(sched) |
ex::then([]() { return 42; }) |
ex::then([](int x) { return std::tuple(x, x * x); }) |
ex::split_tuple();
// snd and snd_squared will be ready at the same time, but can be used
// independently
auto snd_print = std::move(snd) | ex::continues_on(sched) |
ex::then([](int x) { fmt::print("x is {}\n", x); });
auto snd_process = std::move(snd_squared) | ex::continues_on(sched) |
ex::then([](int x_squared) {
fmt::print("Performing expensive operations on x * x\n");
std::this_thread::sleep_for(std::chrono::milliseconds(300));
return x_squared / 2;
});
auto x_squared_processed = tt::sync_wait(
ex::when_all(std::move(snd_print), std::move(snd_process)));
fmt::print("The final result is {}\n", x_squared_processed);
pika::finalize();
pika::stop();
return 0;
}
-
constexpr unpack_t pika::execution::experimental::unpack = {}¶
Transforms a sender of tuples into a sender of the elements of the tuples.
Sender adaptor that takes a sender of a tuple-like and returns a sender where the tuple-like has been unpacked into its elements, similarly to
std::apply
. Each completion signature must send exactly one tuple-like, not zero or more than one. The predecessor sender can have any number of completion signatures for the value channel, each sending a single tuple-like. The adaptor does not unpack tuple-likes recursively. Any type that supports the tuple protocol can be used with the adaptor.
Added in version 0.17.0.
#include <pika/execution.hpp>
#include <pika/init.hpp>
#include <fmt/printf.h>
#include <string>
#include <tuple>
#include <utility>
int main(int argc, char* argv[])
{
namespace ex = pika::execution::experimental;
namespace tt = pika::this_thread::experimental;
pika::start(argc, argv);
ex::thread_pool_scheduler sched{};
auto tuple_sender = ex::just(std::tuple(std::string("hello!"), 42)) |
ex::continues_on(sched);
auto process_data = [](auto message, auto answer) {
fmt::print("{}\nthe answer is: {}\n", message, answer);
};
// With the unpack adaptor, process_data does not have to know that the data
// was originally sent as a tuple
auto unpack_sender = tuple_sender | ex::unpack() | ex::then(process_data);
// We can manually recreate the behaviour of the unpack adaptor by using
// std::apply. This is equivalent to the above.
auto apply_sender = tuple_sender | ex::then([&](auto tuple_of_data) {
return std::apply(process_data, std::move(tuple_of_data));
});
tt::sync_wait(
ex::when_all(std::move(unpack_sender), std::move(apply_sender)));
pika::finalize();
pika::stop();
return 0;
}
-
constexpr when_all_vector_t pika::execution::experimental::when_all_vector = {}¶
Returns a sender that completes when all senders in the input vector have completed.
Sender adaptor that takes a vector of senders and returns a sender that sends a vector of the values sent by the input senders. The vector sent has the same size as the input vector. An empty vector of senders completes immediately on start. When the input vector of senders contains senders that send no value the output sender sends no value instead of a vector. The senders in the input vector must send at most a single type.
Added in version 0.2.0.
#include <pika/execution.hpp>
#include <pika/init.hpp>
#include <fmt/printf.h>
#include <fmt/ranges.h>
#include <cstddef>
#include <random>
#include <utility>
#include <vector>
std::size_t get_n() { return 13; }
std::size_t calculate(std::size_t i) { return (std::rand() % 4) * i * i; }
int main(int argc, char* argv[])
{
namespace ex = pika::execution::experimental;
namespace tt = pika::this_thread::experimental;
pika::start(argc, argv);
ex::thread_pool_scheduler sched{};
// when_all_vector is like when_all, but for a dynamic number of senders
// through a vector of senders
auto const n = get_n();
std::vector<ex::unique_any_sender<std::size_t>> snds;
snds.reserve(n);
for (std::size_t i = 0; i < n; ++i)
{
snds.push_back(
ex::just(i) | ex::continues_on(sched) | ex::then(calculate));
}
auto snds_print = ex::when_all_vector(std::move(snds)) |
ex::then([](std::vector<std::size_t> results) {
fmt::print("Results are: {}\n", fmt::join(results, ", "));
});
tt::sync_wait(std::move(snds_print));
// when_all_vector will send no value on completion if the input vector
// contains senders sending no value
std::vector<ex::unique_any_sender<>> snds_nothing;
snds_nothing.reserve(n);
for (std::size_t i = 0; i < n; ++i)
{
snds_nothing.push_back(ex::just(i) | ex::continues_on(sched) |
ex::then([](auto i) { fmt::print("{}: {}\n", i, calculate(i)); }));
}
auto snds_nothing_done = ex::when_all_vector(std::move(snds_nothing)) |
ex::then([]() { fmt::print("Done printing all results\n"); });
tt::sync_wait(std::move(snds_nothing_done));
pika::finalize();
pika::stop();
return 0;
}