Created on 2025-11-16.00:00:00 last changed 3 weeks ago
Proposed resolution:
This wording is relative to N5014.
[Drafting note: It should be pointed out that member function finish should be `noexcept` for other reasons as well, see LWG 4215.]
Modify [exec.run.loop.general], class `run_loop` synopsis, as indicated:
namespace std::execution {
class run_loop {
// [exec.run.loop.types], associated types
class run-loop-scheduler; // exposition only
class run-loop-sender; // exposition only
struct run-loop-opstate-base { // exposition only
virtual void execute() noexcept = 0; // exposition only
run_loop* loop; // exposition only
run-loop-opstate-base* next; // exposition only
};
template<class Rcvr>
using run-loop-opstate = unspecified; // exposition only
// [exec.run.loop.members], member functions
run-loop-opstate-base* pop-front() noexcept; // exposition only
void push-back(run-loop-opstate-base*) noexcept; // exposition only
public:
// [exec.run.loop.ctor], constructor and destructor
run_loop() noexcept;
run_loop(run_loop&&) = delete;
~run_loop();
// [exec.run.loop.members] member functions
run-loop-scheduler get_scheduler() noexcept;
void run() noexcept;
void finish() noexcept;
};
}
Modify [exec.run.loop.types] as indicated:
class run-loop-sender;-5- run-loop-sender is an exposition-only type that satisfies sender. completion_signatures_of_t<runloop-sender> is
completion_signatures<set_value_t(),set_error_t(exception_ptr),set_stopped_t()>[…]
-9- Let o be a non-const lvalue of type run-loop-opstate<Rcvr>, and let REC(o) be a non-const lvalue reference to an instance of type `Rcvr` that was initialized with the expression rcvr passed to the invocation of connect that returned o. Then:
- (9.1) — […]
- (9.2) — […]
- (9.3) — The expression start(o) is equivalent to:
try {o.loop->push-back(addressof(o));} catch(...) { set_error(std::move(REC(o)), current_exception()); }
Modify [exec.run.loop.members] as indicated:
run-loop-opstate-base* pop-front() noexcept;-1- Effects: Blocks ([defns.block]) until one of the following conditions is `true`: […]
void push-back(run-loop-opstate-base* item) noexcept;-2- Effects: Adds `item` to the back of the queue and increments count by `1`.
-3- Synchronization: This operation synchronizes with the pop-front operation that obtains `item`.run-loop-scheduler get_scheduler() noexcept;-4- Returns: An instance of run-loop-scheduler that can be used to schedule work onto this `run_loop` instance.
void run() noexcept;-5- Preconditions: is either starting or finishing.
-6- Effects: If state is starting, sets the state to running, otherwise leaves state unchanged. Then, equivalent to:while (auto* op = pop-front()) { op->execute(); }-7- Remarks: When state changes, it does so without introducing data races.
void finish() noexcept;-8- Preconditions: state is either starting or running.
-9- Effects: Changes state to finishing. -10- Synchronization: `finish` synchronizes with the pop-front operation that returns `nullptr`.
When `run_loop` was proposed, the only implementation we had synchronized with a mutex and a condition variable. Operations on those can theoretically throw exceptions, so `run_loop` got a `set_error_t(exception_ptr)` completion signature.
Since then, a lock-free implementation of `run_loop` has been found. Atomic operations cannot fail with an exception, so an atomic `run_loop` can never complete with an error.| History | |||
|---|---|---|---|
| Date | User | Action | Args |
| 2025-11-16 16:00:37 | admin | set | messages: + msg15750 |
| 2025-11-16 00:00:00 | admin | create | |