1. Revision History
This paper revises P3669R0 - 2025-04-14 as follows:
-
drops concurrent-op-state and introduces
try_schedule
2. Introduction
Some execution environments want to make sure that specific operations are
non-blocking. These can not signal an event using the facilities of as
currently specified as it doesn’t provide operations
that are guaranteed to be non-blocking.
This became apparent in the proposal for concurrent queues C++ Concurrent Queues (P0260),
which has support for non-blocking usage.
But the non-blocking operations got a very weird interface when interfacing
with due to the lack of non-blocking signalling
to an async waiter.
In the basic operation to signal an event is to schedule
a continuation.
In practice this generally means that a operation is called
on an operation state that comes from a sender provided by a scheduler.
This proposal is independent from C++ Concurrent Queues (P0260) as the problem of signalling an event in a non-blocking way is not specific to concurrent queues.
3. Design
The initial revision of this paper proposed to add a operation to the
operation states that come from a scheduler
and require it to be non-blocking (and to return false if it would block).
After feedback from several people this initial design was dropped.
Instead a new CPO is proposed.
If a on the operation state of a sender returned by would block (e.g. for inserting the operation
into a work queue protected by a mutex),
it immediately calls on the connected receiver.
Unfortunately it is not possible for all kind of schedulers to provide .
Schedulers that are not backed by by an execution context that maintains
a work queue but run the operation right away are an example.
Schedulers that enqueue the work on a different system are another example.
For this reason, this paper proposes a new concept . requires the operation.
While this proposal is generally independent from C++ Concurrent Queues (P0260),
we still would like to fix the weird interface in that proposal if possible.
For this the proposed wording contains a part that modifies the wording
for the queue concepts.
The idea here is to make it ill-formed if an async operation is called
for a queue that also implements and its scheduler
does not implement .
4. Proposed Wording
(Sorry, the wording is still formally horribly incomplete, but I think substantially it’s fairly complete.)
4.1. try_schedule Additions
Add to synopsis in namespace :
struct concurrent_scheduler_t {}; struct would_block_t {};
4.1.1. Concurrent Scheduler Concept
Add to Schedulers [exec.sched]:
-
The concept
defines the requirements of a scheduler type ([async.ops]) that providesconcurrent_scheduler .try_schedule () namespace std :: execution { template < class S , receiver R > concept concurrent_scheduler = std :: derived_from < typename std :: remove_cvref_t < _Scheduler >:: concurrent_scheduler_concept , concurrent_scheduler_t > && scheduler < S > && requires ( S && s ) { { try_schedule ( std :: forward < S > ( s )) } -> sender ; } }
4.1.2. execution :: try_schedule
Add to Sender facories [exec.factories]:
-
obtains a schedule sender ([exec.async.ops]) from a scheduler to potentially start an asynchronous operation without blocking ([defns.block]).try_schedule -
The name
denotes a customization point object. For a subexpressiontry_schedule , the expressionsch is expression-equivalent totry_schedule ( sch ) .sch . try_schedule () -
Mandates: The type of
satisfiessch . try_schedule () .sender -
If the expression
is ill-formed or evaluates toget_completion_scheduler < set_value_t > ( get_env ( sch . try_schedule ())) == sch false, the behavior of callingis undefined.try_schedule ( sch ) -
The expression
has the following semantics:sch . try_schedule () -
Let
be a sender object returned by the expression, andw be an operation state obtained from connectingop to a receiverw .r -
Returns: A sender object
that behaves as follows:w -
starts ([async.ops]) the asynchronous operation associated withop . start () , if it can be achieved without blocking.op -
If starting the asynchronous operation would block, it immediately calls
.set_error ( r , would_block_t ())
-
-
4.1.3. run_loop
-
run-loop-scheduler models
.concurrent_scheduler
4.2. Modifications for Concurrent Queues
Remove from the enumeration and the respective
return statements from , and in the concurrent-queue concept.
In the async-concurrent-queue concept add another bullet to the senders
returned by and after bullet 6:
-
If the scheduler of
does not modelr , the program is ill-formed.concurrent_scheduler