std::execution::run_loop
| Defined in header <execution>
|
||
class run_loop
{
public:
run_loop() noexcept;
run_loop(run_loop&&) = delete;
~run_loop();
/*run-loop-scheduler*/ get_scheduler() noexcept;
void run() noexcept;
void finish() noexcept;
};
|
(since C++26) | |
run_loop is a lightweight execution resource that owns a thread-safe first-in-first-out queue of work, usable as a manually-driven event loop. A scheduler obtained from a run_loop schedules work onto that queue, and run executes queued work on the calling thread.
The type is primarily useful for tests, examples, and simple event-loop style execution. It does not create a thread by itself: a program decides which thread calls run.
Member functions
constructs a run_loop (public member function) | |
destroys the run_loop (public member function) | |
obtains a scheduler associated with the run_loop (public member function) | |
| runs queued work on the calling thread (public member function) | |
requests the run_loop to finish (public member function) |
Associated scheduler
get_scheduler returns an object of unspecified type, denoted here as /*run-loop-scheduler*/.
Schedulers obtained from the same run_loop compare equal. Schedulers obtained from different run_loop objects compare unequal. A scheduler obtained from a run_loop remains valid only while the corresponding run_loop object is alive.
Calling schedule on a run_loop scheduler returns a sender. The sender completes with set_value() when the scheduled work is executed. If the receiver's stop token is stoppable, the sender may instead complete with set_stopped() if stop is already requested before the operation runs.
Execution
A run_loop maintains an internal state (which can be one of starting, running, finishing, or finished) and a count of queued operation states.
run may be called when the loop has not yet started or has been requested to finish. If the loop has not yet started, run changes it to the running state. It then repeatedly removes the first queued operation state and executes it. If no work is available, run blocks until work is queued or the loop is ready to finish. run returns after finish has been requested and all queued work has been executed.
finish requests the loop to finish. It can be called before or during run, and it wakes a blocked run call so that it can return once the queue has drained.
Destroying a run_loop while it is running or while operation states remain queued calls std::terminate.
Notes
Starting an operation state created from a run_loop scheduler enqueues the operation. The operation's receiver is completed later, when a thread executing run removes that operation from the queue.
Except for concurrent calls to run itself and destruction of the object, operations on a run_loop do not introduce data races.
Example
A run_loop can be used to back a simple single-threaded execution context.
#include <execution>
#include <iostream>
#include <thread>
class single_thread_context
{
std::execution::run_loop loop_;
std::jthread worker_;
public:
single_thread_context()
: worker_([this] { loop_.run(); })
{}
~single_thread_context()
{
loop_.finish();
}
auto get_scheduler() noexcept
{
return loop_.get_scheduler();
}
};
int main()
{
namespace ex = std::execution;
single_thread_context ctx;
auto snd =
ex::schedule(ctx.get_scheduler())
| ex::then([] {
std::cout << "work runs on the loop\n";
return 42;
});
auto [value] = std::this_thread::sync_wait(std::move(snd)).value();
std::cout << value << '\n';
}
Output:
work runs on the loop
42
See also
(C++26) |
specifies that a type is a scheduler (concept) |
(C++26) |
prepares a task graph for execution on a given scheduler (customization point object) |