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 calling
is 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