This page is a snapshot from the LWG issues list, see the Library Active Issues List for more information and the meaning of New status.
run_loop should not have a set_error completionSection: 33.12.1.1 [exec.run.loop.general] Status: New Submitter: Eric Niebler Opened: 2025-11-16 Last modified: 2025-11-16
Priority: Not Prioritized
View all issues with New status.
Discussion:
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.
run_loop has been found. Atomic operations cannot fail with an exception,
so an atomic run_loop can never complete with an error.
Proposed resolution:
This wording is relative to N5014.
[Drafting note: It should be pointed out that member function
finishshould benoexceptfor other reasons as well, see LWG 4215(i).]
Modify 33.12.1.1 [exec.run.loop.general], class run_loop synopsis, as indicated:
namespace std::execution {
class run_loop {
// 33.12.1.2 [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
// 33.12.1.4 [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:
// 33.12.1.3 [exec.run.loop.ctor], constructor and destructor
run_loop() noexcept;
run_loop(run_loop&&) = delete;
~run_loop();
// 33.12.1.4 [exec.run.loop.members] member functions
run-loop-scheduler get_scheduler() noexcept;
void run() noexcept;
void finish() noexcept;
};
}
Modify 33.12.1.2 [exec.run.loop.types] as indicated:
class run-loop-sender;-5-
run-loop-senderis an exposition-only type that satisfies sender.completion_signatures_of_t<runloop-sender>iscompletion_signatures<set_value_t(),set_error_t(exception_ptr),set_stopped_t()>[…]
-9- Letobe a non-const lvalue of typerun-loop-opstate<Rcvr>, and letREC(o)be a non-const lvalue reference to an instance of typeRcvrthat was initialized with the expressionrcvrpassed to the invocation of connect that returnedo. 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 33.12.1.4 [exec.run.loop.members] as indicated:
run-loop-opstate-base* pop-front() noexcept;-1- Effects: Blocks (3.6 [defns.block]) until one of the following conditions is
true: […]void push-back(run-loop-opstate-base* item) noexcept;-2- Effects: Adds
-3- Synchronization: This operation synchronizes with theitemto the back of the queue and incrementscountby1.pop-frontoperation that obtainsitem.run-loop-scheduler get_scheduler() noexcept;-4- Returns: An instance of
run-loop-schedulerthat can be used to schedule work onto thisrun_loopinstance.void run() noexcept;-5- Preconditions: is either
-6- Effects: Ifstartingorfinishing.stateisstarting, sets thestatetorunning, otherwise leavesstateunchanged. Then, equivalent to:while (auto* op = pop-front()) { op->execute(); }-7- Remarks: When
statechanges, it does so without introducing data races.void finish() noexcept;-8- Preconditions:
-9- Effects: Changesstateis eitherstartingorrunning.statetofinishing. -10- Synchronization:finishsynchronizes with thepop-frontoperation that returnsnullptr.