32 Concurrency support library [thread]

32.3 Stop tokens [thread.stoptoken]

32.3.3 Stop token concepts [stoptoken.concepts]

The exposition-only stoppable-callback-for concept checks for a callback compatible with a given Token type.
template<class CallbackFn, class Token, class Initializer = CallbackFn> concept stoppable-callback-for = // exposition only invocable<CallbackFn> && constructible_from<CallbackFn, Initializer> && requires { typename stop_callback_for_t<Token, CallbackFn>; } && constructible_from<stop_callback_for_t<Token, CallbackFn>, const Token&, Initializer>;
Let t and u be distinct, valid objects of type Token that reference the same logical stop state; let init be an expression such that same_as<decltype(init), Initializer> is true; and let SCB denote the type stop_callback_for_t<Token, CallbackFn>.
The concept stoppable-callback-for<CallbackFn, Token, Initializer> is modeled only if:
  • The following concepts are modeled:
  • An object of type SCB has an associated callback function of type CallbackFn.
    Let scb be an object of type SCB and let callback_fn denote scb's associated callback function.
    Direct-non-list-initializing scb from arguments t and init shall execute a stoppable callback registration as follows:
    • If t.stop_possible() is true:
      • callback_fn shall be direct-initialized with init.
      • Construction of scb shall only throw exceptions thrown by the initialization of callback_fn from init.
      • The callback invocation std​::​forward<CallbackFn>(callback_fn)() shall be registered with t's associated stop state as follows:
        • If t.stop_requested() evaluates to false at the time of registration, the callback invocation is added to the stop state's list of callbacks such that std​::​forward<CallbackFn>(
          callback_fn)()
          is evaluated if a stop request is made on the stop state.
        • Otherwise, std​::​forward<CallbackFn>(callback_fn)() shall be immediately evaluated on the thread executing scb's constructor, and the callback invocation shall not be added to the list of callback invocations.
        If the callback invocation was added to stop state's list of callbacks, scb shall be associated with the stop state.
    • [Note 1: 
      If t.stop_possible() is false, there is no requirement that the initialization of scb causes the initialization of callback_fn.
      — end note]
  • Destruction of scb shall execute a stoppable callback deregistration as follows (in order):
    • If the constructor of scb did not register a callback invocation with t's stop state, then the stoppable callback deregistration shall have no effect other than destroying callback_fn if it was constructed.
    • Otherwise, the invocation of callback_fn shall be removed from the associated stop state.
    • If callback_fn is concurrently executing on another thread, then the stoppable callback deregistration shall block ([defns.block]) until the invocation of callback_fn returns such that the return from the invocation of callback_fn strongly happens before ([intro.races]) the destruction of callback_fn.
    • If callback_fn is executing on the current thread, then the destructor shall not block waiting for the return from the invocation of callback_fn.
    • A stoppable callback deregistration shall not block on the completion of the invocation of some other callback registered with the same logical stop state.
    • The stoppable callback deregistration shall destroy callback_fn.
The stoppable_token concept checks for the basic interface of a stop token that is copyable and allows polling to see if stop has been requested and also whether a stop request is possible.
The unstoppable_token concept checks for a stoppable_token type that does not allow stopping.
template<template<class> class> struct check-type-alias-exists; // exposition only template<class Token> concept stoppable_token = requires (const Token tok) { typename check-type-alias-exists<Token::template callback_type>; { tok.stop_requested() } noexcept -> same_as<bool>; { tok.stop_possible() } noexcept -> same_as<bool>; { Token(tok) } noexcept; // see implicit expression variations ([concepts.equality]) } && copyable<Token> && equality_comparable<Token>; template<class Token> concept unstoppable_token = stoppable_token<Token> && requires (const Token tok) { requires bool_constant<(!tok.stop_possible())>::value; };
An object whose type models stoppable_token has at most one associated logical stop state.
A stoppable_token object with no associated stop state is said to be disengaged.
Let SP be an evaluation of t.stop_possible() that is false, and let SR be an evaluation of t.stop_requested() that is true.
The type Token models stoppable_token only if:
  • Any evaluation of u.stop_possible() or u.stop_requested() that happens after ([intro.races]) SP is false.
  • Any evaluation of u.stop_possible() or u.stop_requested() that happens after SR is true.
  • For any types CallbackFn and Initializer such that stoppable-callback-for<CallbackFn, Token, Initializer> is satisfied, stoppable-callback-for<CallbackFn, Token, Initializer> is modeled.
  • If t is disengaged, evaluations of t.stop_possible() and t.stop_requested() are false.
  • If t and u reference the same stop state, or if both t and u are disengaged, t == u is true; otherwise, it is false.
An object whose type models the exposition-only stoppable-source concept can be queried whether stop has been requested (stop_requested) and whether stop is possible (stop_possible).
It is a factory for associated stop tokens (get_token), and a stop request can be made on it (request_stop).
It maintains a list of registered stop callback invocations that it executes when a stop request is first made.
template<class Source> concept stoppable-source = // exposition only requires (Source& src, const Source csrc) { // see implicit expression variations ([concepts.equality]) { csrc.get_token() } -> stoppable_token; { csrc.stop_possible() } noexcept -> same_as<bool>; { csrc.stop_requested() } noexcept -> same_as<bool>; { src.request_stop() } -> same_as<bool>; };
An object whose type models stoppable-source has at most one associated logical stop state.
If it has no associated stop state, it is said to be disengaged.
Let s be an object whose type models stoppable-source and that is disengaged.
s.stop_possible() and s.stop_requested() shall be false.
Let t be an object whose type models stoppable-source.
If t is disengaged, t.get_token() shall return a disengaged stop token; otherwise, it shall return a stop token that is associated with the stop state of t.
Calls to the member functions request_stop, stop_requested, and stop_possible and similarly named member functions on associated stoppable_token objects do not introduce data races.
A call to request_stop that returns true synchronizes with a call to stop_requested on an associated stoppable_token or stoppable-source object that returns true.
Registration of a callback synchronizes with the invocation of that callback.
If the stoppable-source is disengaged, request_stop shall have no effect and return false.
Otherwise, it shall execute a stop request operation on the associated stop state.
A stop request operation determines whether the stop state has received a stop request, and if not, makes a stop request.
The determination and making of the stop request shall happen atomically, as-if by a read-modify-write operation ([intro.races]).
If the request was made, the stop state's registered callback invocations shall be synchronously executed.
If an invocation of a callback exits via an exception then terminate shall be invoked ([except.terminate]).
[Note 2: 
No constraint is placed on the order in which the callback invocations are executed.
— end note]
request_stop shall return true if a stop request was made, and false otherwise.
After a call to request_stop either a call to stop_possible shall return false or a call to stop_requested shall return true.
[Note 3: 
A stop request includes notifying all condition variables of type condition_variable_any temporarily registered during an interruptible wait ([thread.condvarany.intwait]).
— end note]