Files
cppdraft_translate/cppdraft/exec/ctx.md
2025-10-25 03:02:53 +03:00

12 KiB
Raw Blame History

[exec.ctx]

33 Execution control library [exec]

33.12 Execution contexts [exec.ctx]

33.12.1 execution::run_loop [exec.run.loop]

33.12.1.1 General [exec.run.loop.general]

1

#

A run_loop is an execution resource on which work can be scheduled.

It maintains a thread-safe first-in-first-out queue of work.

Its run member function removes elements from the queue and executes them in a loop on the thread of execution that calls run.

2

#

A run_loop instance has an associated count that corresponds to the number of work items that are in its queue.

Additionally, a run_loop instance has an associated state that can be one ofstarting, running, finishing, or finished.

3

#

Concurrent invocations of the member functions of run_loop other than run and its destructor do not introduce data races.

The member functionspop-front, push-back, and finish execute atomically.

4

#

Recommended practice: Implementations should use an intrusive queue of operation states to hold the work units to make scheduling allocation-free.

namespace std::execution {class run_loop {// [exec.run.loop.types], associated typesclass run-loop-scheduler; // exposition onlyclass run-loop-sender; // exposition onlystruct run-loop-opstate-base { // exposition onlyvirtual void execute() = 0; // exposition only run_loop* loop; // exposition onlyrun-loop-opstate-base next; // exposition only}; templateusing run-loop-opstate = unspecified; // exposition only// [exec.run.loop.members], member functionsrun-loop-opstate-base** pop-front(); // exposition onlyvoid push-back(run-loop-opstate-base*); // exposition onlypublic:// [exec.run.loop.ctor], constructor and destructor run_loop() noexcept; run_loop(run_loop&&) = delete; ~run_loop(); // [exec.run.loop.members], member functionsrun-loop-scheduler get_scheduler(); void run(); void finish(); };}

33.12.1.2 Associated types [exec.run.loop.types]

🔗

class run-loop-scheduler;

1

#

run-loop-scheduler is an unspecified type that models scheduler.

2

#

Instances of run-loop-scheduler remain valid until the end of the lifetime of the run_loop instance from which they were obtained.

3

#

Two instances of run-loop-scheduler compare equal if and only if they were obtained from the same run_loop instance.

4

#

Let sch be an expression of type run-loop-scheduler.

The expression schedule(sch) has type run-loop-
sender
and is not potentially-throwing if sch is not potentially-throwing.

🔗

class run-loop-sender;

5

#

run-loop-sender is an exposition-only type that satisfies sender.

completion_signatures_of_t<run-
loop-sender
> iscompletion_signatures<set_value_t(), set_error_t(exception_ptr), set_stopped_t()>

6

#

An instance of run-loop-sender remains valid until the end of the lifetime of its associated run_loop instance.

7

#

Let sndr be an expression of type run-loop-sender, let rcvr be an expression such that receiver_of<decltype((rcvr)), CS> is true where CS is the completion_signatures specialization above.

Let C be either set_value_t or set_stopped_t.

Then:

  • (7.1)

    The expression connect(sndr, rcvr) has type run-loop-opstate<decay_t<decltype((rcvr))>> and is potentially-throwing if and only if(void(sndr), auto(rcvr)) is potentially-throwing.

  • (7.2)

    The expression get_completion_scheduler(get_env(sndr)) is potentially-throwing if and only if sndr is potentially-throwing, has type run-loop-scheduler, and compares equal to the run-loop-
    scheduler
    instance from which sndr was obtained.

🔗

template<class Rcvr> struct run-loop-opstate;

8

#

run-loop-opstate inherits privately and unambiguously from run-loop-opstate-base.

9

#

Let o be a non-const lvalue of type run-loop-opstate, 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:

The object to which REC(o) refers remains valid for the lifetime of the object to which o refers.

The type run-loop-opstate overridesrun-loop-opstate-base::execute() such that o.execute() is equivalent to:if (get_stop_token(REC(o)).stop_requested()) { set_stopped(std::move(REC(o)));} else { set_value(std::move(REC(o)));}

The expression start(o) is equivalent to:try {o.loop->push-back(addressof(o));} catch(...) { set_error(std::move(REC(o)), current_exception());}

33.12.1.3 Constructor and destructor [exec.run.loop.ctor]

🔗

run_loop() noexcept;

1

#

Postconditions: count is 0 and state is starting.

🔗

~run_loop();

2

#

Effects: If count is not 0 or if state is running, invokes terminate ([except.terminate]).

Otherwise, has no effects.

33.12.1.4 Member functions [exec.run.loop.members]

🔗

run-loop-opstate-base* pop-front();

1

#

Effects: Blocks ([defns.block]) until one of the following conditions is true:

count is 0 and state is finishing, in which case pop-front sets state to finished and returns nullptr; or

count is greater than 0, in which case an item is removed from the front of the queue,count is decremented by 1, and the removed item is returned.

🔗

void push-back(run-loop-opstate-base* item);

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();

4

#

Returns: An instance of run-loop-scheduler that can be used to schedule work onto this run_loop instance.

🔗

void run();

5

#

Preconditions: state 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();

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.