32 Concurrency support library [thread]

32.3 Stop tokens [thread.stoptoken]

32.3.1 Introduction [thread.stoptoken.intro]

Subclause [thread.stoptoken] describes components that can be used to asynchronously request that an operation stops execution in a timely manner, typically because the result is no longer required.
Such a request is called a stop request.
The concepts stoppable-source, stoppable_token, and stoppable-callback-for specify the required syntax and semantics of shared access to a stop state.
Any object modeling stoppable-source, stoppable_token, or stoppable-callback-for that refers to the same stop state is an associated stoppable-source, stoppable_token, or stoppable-callback-for, respectively.
An object of a type that models stoppable_token can be passed to an operation that can either
  • actively poll the token to check if there has been a stop request, or
  • register a callback that will be called in the event that a stop request is made.
A stop request made via an object whose type models stoppable-source will be visible to all associated stoppable_token and stoppable-source objects.
Once a stop request has been made it cannot be withdrawn (a subsequent stop request has no effect).
Callbacks registered via an object whose type models stoppable-callback-for are called when a stop request is first made by any associated stoppable-source object.
The types stop_source and stop_token and the class template stop_callback implement the semantics of shared ownership of a stop state.
The last remaining owner of the stop state automatically releases the resources associated with the stop state.
An object of type inplace_stop_source is the sole owner of its stop state.
An object of type inplace_stop_token or of a specialization of the class template inplace_stop_callback does not participate in ownership of its associated stop state.
[Note 1: 
They are for use when all uses of the associated token and callback objects are known to nest within the lifetime of the inplace_stop_source object.
— end note]

32.3.2 Header <stop_token> synopsis [thread.stoptoken.syn]

namespace std { // [stoptoken.concepts], stop token concepts template<class CallbackFn, class Token, class Initializer = CallbackFn> concept stoppable-callback-for = see below; // exposition only template<class Token> concept stoppable_token = see below; template<class Token> concept unstoppable_token = see below; template<class Source> concept stoppable-source = see below; // exposition only // [stoptoken], class stop_token class stop_token; // [stopsource], class stop_source class stop_source; // no-shared-stop-state indicator struct nostopstate_t { explicit nostopstate_t() = default; }; inline constexpr nostopstate_t nostopstate{}; // [stopcallback], class template stop_callback template<class Callback> class stop_callback; // [stoptoken.never], class never_stop_token class never_stop_token; // [stoptoken.inplace], class inplace_stop_token class inplace_stop_token; // [stopsource.inplace], class inplace_stop_source class inplace_stop_source; // [stopcallback.inplace], class template inplace_stop_callback template<class CallbackFn> class inplace_stop_callback; template<class T, class CallbackFn> using stop_callback_for_t = T::template callback_type<CallbackFn>; }

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]

32.3.4 Class stop_token [stoptoken]

32.3.4.1 General [stoptoken.general]

The class stop_token models the concept stoppable_token.
It shares ownership of its stop state, if any, with its associated stop_source object ([stopsource]) and any stop_token objects to which it compares equal.
namespace std { class stop_token { public: template<class CallbackFn> using callback_type = stop_callback<CallbackFn>; stop_token() noexcept = default; // [stoptoken.mem], member functions void swap(stop_token&) noexcept; bool stop_requested() const noexcept; bool stop_possible() const noexcept; bool operator==(const stop_token& rhs) noexcept = default; private: shared_ptr<unspecified> stop-state; // exposition only }; }
stop-state refers to the stop_token's associated stop state.
A stop_token object is disengaged when stop-state is empty.

32.3.4.2 Member functions [stoptoken.mem]

void swap(stop_token& rhs) noexcept;
Effects: Equivalent to: stop-state.swap(rhs.stop-state);
bool stop_requested() const noexcept;
Returns: true if stop-state refers to a stop state that has received a stop request; otherwise, false.
bool stop_possible() const noexcept;
Returns: false if
  • *this is disengaged, or
  • a stop request was not made and there are no associated stop_source objects;
otherwise, true.

32.3.5 Class stop_source [stopsource]

32.3.5.1 General [stopsource.general]

namespace std { class stop_source { public: // [stopsource.cons], constructors, copy, and assignment stop_source(); explicit stop_source(nostopstate_t) noexcept {} // [stopsource.mem], member functions void swap(stop_source&) noexcept; bool request_stop() noexcept; bool operator==(const stop_source& rhs) noexcept = default; private: shared_ptr<unspecified> stop-state; // exposition only }; }
stop-state refers to the stop_source's associated stop state.
A stop_source object is disengaged when stop-state is empty.

32.3.5.2 Constructors, copy, and assignment [stopsource.cons]

stop_source();
Effects: Initializes stop-state with a pointer to a new stop state.
Postconditions: stop_possible() is true and stop_requested() is false.
Throws: bad_alloc if memory cannot be allocated for the stop state.

32.3.5.3 Member functions [stopsource.mem]

void swap(stop_source& rhs) noexcept;
Effects: Equivalent to: stop-state.swap(rhs.stop-state);
stop_token get_token() const noexcept;
Returns: stop_token() if stop_possible() is false; otherwise a new associated stop_token object; i.e., its stop-state member is equal to the stop-state member of *this.
bool stop_possible() const noexcept;
Returns: stop-state != nullptr.
bool stop_requested() const noexcept;
Returns: true if stop-state refers to a stop state that has received a stop request; otherwise, false.
bool request_stop() noexcept;
Effects: Executes a stop request operation ([stoptoken.concepts]) on the associated stop state, if any.

32.3.6 Class template stop_callback [stopcallback]

32.3.6.1 General [stopcallback.general]

namespace std { template<class CallbackFn> class stop_callback { public: using callback_type = CallbackFn; // [stopcallback.cons], constructors and destructor template<class Initializer> explicit stop_callback(const stop_token& st, Initializer&& init) noexcept(is_nothrow_constructible_v<CallbackFn, Initializer>); template<class Initializer> explicit stop_callback(stop_token&& st, Initializer&& init) noexcept(is_nothrow_constructible_v<CallbackFn, Initializer>); ~stop_callback(); stop_callback(const stop_callback&) = delete; stop_callback(stop_callback&&) = delete; stop_callback& operator=(const stop_callback&) = delete; stop_callback& operator=(stop_callback&&) = delete; private: CallbackFn callback-fn; // exposition only }; template<class CallbackFn> stop_callback(stop_token, CallbackFn) -> stop_callback<CallbackFn>; }
Mandates: stop_callback is instantiated with an argument for the template parameter CallbackFn that satisfies both invocable and destructible.
Remarks: For a type Initializer, if stoppable-callback-for<CallbackFn, stop_token, Initializer> is satisfied, then stoppable-callback-for<CallbackFn, stop_token, Initializer> is modeled.
The exposition-only callback-fn member is the associated callback function ([stoptoken.concepts]) of stop_callback<
CallbackFn>
objects.

32.3.6.2 Constructors and destructor [stopcallback.cons]

template<class Initializer> explicit stop_callback(const stop_token& st, Initializer&& init) noexcept(is_nothrow_constructible_v<CallbackFn, Initializer>); template<class Initializer> explicit stop_callback(stop_token&& st, Initializer&& init) noexcept(is_nothrow_constructible_v<CallbackFn, Initializer>);
Constraints: CallbackFn and Initializer satisfy constructible_from<CallbackFn, Initializer>.
Effects: Initializes callback-fn with std​::​forward<Initializer>(init) and executes a stoppable callback registration ([stoptoken.concepts]).
If a callback is registered with st's shared stop state, then *this acquires shared ownership of that stop state.
~stop_callback();
Effects: Executes a stoppable callback deregistration ([stoptoken.concepts]) and releases ownership of the stop state, if any.

32.3.7 Class never_stop_token [stoptoken.never]

The class never_stop_token models the unstoppable_token concept.
It provides a stop token interface, but also provides static information that a stop is never possible nor requested.
namespace std { class never_stop_token { struct callback-type { // exposition only explicit callback-type(never_stop_token, auto&&) noexcept {} }; public: template<class> using callback_type = callback-type; static constexpr bool stop_requested() noexcept { return false; } static constexpr bool stop_possible() noexcept { return false; } bool operator==(const never_stop_token&) const = default; }; }

32.3.8 Class inplace_stop_token [stoptoken.inplace]

32.3.8.1 General [stoptoken.inplace.general]

The class inplace_stop_token models the concept stoppable_token.
It references the stop state of its associated inplace_stop_source object ([stopsource.inplace]), if any.
namespace std { class inplace_stop_token { public: template<class CallbackFn> using callback_type = inplace_stop_callback<CallbackFn>; inplace_stop_token() = default; bool operator==(const inplace_stop_token&) const = default; // [stoptoken.inplace.mem], member functions bool stop_requested() const noexcept; bool stop_possible() const noexcept; void swap(inplace_stop_token&) noexcept; private: const inplace_stop_source* stop-source = nullptr; // exposition only }; }

32.3.8.2 Member functions [stoptoken.inplace.mem]

void swap(inplace_stop_token& rhs) noexcept;
Effects: Exchanges the values of stop-source and rhs.stop-source.
bool stop_requested() const noexcept;
Effects: Equivalent to: return stop-source != nullptr && stop-source->stop_requested();
[Note 1: 
As specified in [basic.life], the behavior of stop_requested is undefined unless the call strongly happens before the start of the destructor of the associated inplace_stop_source object, if any.
— end note]
stop_possible() const noexcept;
Returns: stop-source != nullptr.
[Note 2: 
As specified in [basic.stc.general], the behavior of stop_possible is implementation-defined unless the call strongly happens before the end of the storage duration of the associated inplace_stop_source object, if any.
— end note]

32.3.9 Class inplace_stop_source [stopsource.inplace]

32.3.9.1 General [stopsource.inplace.general]

The class inplace_stop_source models stoppable-source.
namespace std { class inplace_stop_source { public: // [stopsource.inplace.cons], constructors constexpr inplace_stop_source() noexcept; inplace_stop_source(inplace_stop_source&&) = delete; inplace_stop_source(const inplace_stop_source&) = delete; inplace_stop_source& operator=(inplace_stop_source&&) = delete; inplace_stop_source& operator=(const inplace_stop_source&) = delete; ~inplace_stop_source(); // [stopsource.inplace.mem], stop handling constexpr inplace_stop_token get_token() const noexcept; static constexpr bool stop_possible() noexcept { return true; } bool stop_requested() const noexcept; bool request_stop() noexcept; }; }

32.3.9.2 Constructors [stopsource.inplace.cons]

constexpr inplace_stop_source() noexcept;
Effects: Initializes a new stop state inside *this.
Postconditions: stop_requested() is false.

32.3.9.3 Member functions [stopsource.inplace.mem]

constexpr inplace_stop_token get_token() const noexcept;
Returns: A new associated inplace_stop_token object whose stop-source member is equal to this.
bool stop_requested() const noexcept;
Returns: true if the stop state inside *this has received a stop request; otherwise, false.
bool request_stop() noexcept;
Effects: Executes a stop request operation ([stoptoken.concepts]).
Postconditions: stop_requested() is true.

32.3.10 Class template inplace_stop_callback [stopcallback.inplace]

32.3.10.1 General [stopcallback.inplace.general]

namespace std { template<class CallbackFn> class inplace_stop_callback { public: using callback_type = CallbackFn; // [stopcallback.inplace.cons], constructors and destructor template<class Initializer> explicit inplace_stop_callback(inplace_stop_token st, Initializer&& init) noexcept(is_nothrow_constructible_v<CallbackFn, Initializer>); ~inplace_stop_callback(); inplace_stop_callback(inplace_stop_callback&&) = delete; inplace_stop_callback(const inplace_stop_callback&) = delete; inplace_stop_callback& operator=(inplace_stop_callback&&) = delete; inplace_stop_callback& operator=(const inplace_stop_callback&) = delete; private: CallbackFn callback-fn; // exposition only }; template<class CallbackFn> inplace_stop_callback(inplace_stop_token, CallbackFn) -> inplace_stop_callback<CallbackFn>; }
Mandates: CallbackFn satisfies both invocable and destructible.
Remarks: For a type Initializer, if stoppable-callback-for<CallbackFn, inplace_stop_token, Initializer> is satisfied, then stoppable-callback-for<CallbackFn, inplace_stop_token, Initializer> is modeled.
For an inplace_stop_callback<CallbackFn> object, the exposition-only callback-fn member is its associated callback function ([stoptoken.concepts]).

32.3.10.2 Constructors and destructor [stopcallback.inplace.cons]

template<class Initializer> explicit inplace_stop_callback(inplace_stop_token st, Initializer&& init) noexcept(is_nothrow_constructible_v<CallbackFn, Initializer>);
Constraints: constructible_from<CallbackFn, Initializer> is satisfied.
Effects: Initializes callback-fn with std​::​forward<Initializer>(init) and executes a stoppable callback registration ([stoptoken.concepts]).
~inplace_stop_callback();
Effects: Executes a stoppable callback deregistration ([stoptoken.concepts]).