| Document number: | P3472R0 | |
|---|---|---|
| Date: | 2024-10-15 | |
| Audience: | LEWG | |
| Reply-to: | Andrzej Krzemieński <akrzemi1 at gmail dot com> |
fiber_context::can_resume() const We propose to change the signature of function fiber_context::can_resume()
so that it is a const member function.
[P0876R17]
proposes a great library, fiber_context, providing an API for stackful
context switching, based on
Boost.Context.
It has one unusual design point in its interface. Member function
fiber_context::can_resume(), which tells if the given fiber can be resumed
by the calling thread, which is used as a precondition for other
member functions in fiber_context is not declared
const, implying that it cannot be called concurrently, without external
synchronization, from multiple threads.
The older revision of the paper,
[P0876R6],
gives the rationale for making this function non-const.
can_resume()is not markedconstbecause in at least one implementation, it requires an internal context switch. However, the stack operations are effectively read-only. Nonetheless, if it is possible for more than one thread to callcan_resume()concurrently on the same non-emptystd::fiber_contextinstance, locking is the caller’s responsibility.
Given this potential data race, it is
conceptually difficult to accept that it is a predicate suitable for use as a function
precondition. In the context of the proposed contract support framework ([P2900R9]),
function fiber_context::can_resume() would not be usable in contract assertions,
as they always treat objects used in the predicates as const.
We believe that this "not const" provision is not necessary. The functionality of
can_resume() can be implemented under a hosted implementation by storing
the result of std::this_thread::get_id() upon the first fiber resumption
and comparing it against the result of std::this_thread::get_id() performed
inside can_resume(). This technique is used in the
reference implementation.
Under a freestanding implementation can_resume() can be implemented as
!empty().