Date: Sat, 15 Jul 2023 09:40:23 -0400
On Sat, Jul 15, 2023 at 9:27 AM Yuri Petrenko via Std-Proposals
<std-proposals_at_[hidden]> wrote:
>
> It's great that Linux already has something to rely on, but there is a subtle difference. In the case you mentioned, as far as I understand, pthread_cancel will ask the thread to cancel, and this will be possible only when we reach the Cancelation point, this mechanism is much better than a stop token, but very similar to it. In case of RAII thread we can interrupt the execution thread immediately without waiting for Cancelation point or token check, except for a few intervals like prologue and epilogue, destructor (destructors need to be discussed in detail), etc., where special handling is needed.
> In case of pthread there are points at which we cancel the thread, in case of RAII thread there are certain intervals at which we can/can't destroy it. The gist of this idea is that if the thread corresponds to RAII as a whole, it is not necessary to wait for Cancellation point.
Is it though? Is it really?
Even code that follows RAII principles religiously will have places
where cancellation at various points will cause breakage. I'm going to
model your cancellation feature as "throwing an exception into someone
else's call-stack".
Consider `make_unique`. Somewhere in this function is code that
reduces down to this:
unique_ptr<T>(new T(...));
In the evaluation of that expression, there is a point where `new T()`
has been executed but *not* the constructor of `unique_ptr`. Until
that constructor has finished executing, the pointer is not owned by
anyone.
However, this is fine. `unique_ptr`;s constructor is `noexcept`, the
initialization of its parameters are all `noexcept`, and if the `new`
expression throws, there is no pointer to manage. So between a
successful evaluation of `new T` and the completion of `unique_ptr`'s
constructor, no exceptions can possibly be thrown. Therefore, this
code is exception-safe.
If you can cancel a thread (throw an exception into the call-stack) at
any point, then you could cancel it at the precise point where no
exceptions could have otherwise been thrown. That's... bad.
Code can be exception-safe, but that's only because there are places
where it is guaranteed that no exceptions can be thrown. Cancellation
*must* work the same way: there must be places where you *cannot*
cancel a thread. RAII can encapsulate those into constructors and
functions returning prvalues, but that just puts the uncancellable
code inside of specific blocks. It still exists and still must be
uncancellable.
> In general, I would really like to use the handler mechanism you mentioned. I'll be sure to add the relevant part to the discussion, thank you.
> --
> Std-Proposals mailing list
> Std-Proposals_at_[hidden]
> https://lists.isocpp.org/mailman/listinfo.cgi/std-proposals
<std-proposals_at_[hidden]> wrote:
>
> It's great that Linux already has something to rely on, but there is a subtle difference. In the case you mentioned, as far as I understand, pthread_cancel will ask the thread to cancel, and this will be possible only when we reach the Cancelation point, this mechanism is much better than a stop token, but very similar to it. In case of RAII thread we can interrupt the execution thread immediately without waiting for Cancelation point or token check, except for a few intervals like prologue and epilogue, destructor (destructors need to be discussed in detail), etc., where special handling is needed.
> In case of pthread there are points at which we cancel the thread, in case of RAII thread there are certain intervals at which we can/can't destroy it. The gist of this idea is that if the thread corresponds to RAII as a whole, it is not necessary to wait for Cancellation point.
Is it though? Is it really?
Even code that follows RAII principles religiously will have places
where cancellation at various points will cause breakage. I'm going to
model your cancellation feature as "throwing an exception into someone
else's call-stack".
Consider `make_unique`. Somewhere in this function is code that
reduces down to this:
unique_ptr<T>(new T(...));
In the evaluation of that expression, there is a point where `new T()`
has been executed but *not* the constructor of `unique_ptr`. Until
that constructor has finished executing, the pointer is not owned by
anyone.
However, this is fine. `unique_ptr`;s constructor is `noexcept`, the
initialization of its parameters are all `noexcept`, and if the `new`
expression throws, there is no pointer to manage. So between a
successful evaluation of `new T` and the completion of `unique_ptr`'s
constructor, no exceptions can possibly be thrown. Therefore, this
code is exception-safe.
If you can cancel a thread (throw an exception into the call-stack) at
any point, then you could cancel it at the precise point where no
exceptions could have otherwise been thrown. That's... bad.
Code can be exception-safe, but that's only because there are places
where it is guaranteed that no exceptions can be thrown. Cancellation
*must* work the same way: there must be places where you *cannot*
cancel a thread. RAII can encapsulate those into constructors and
functions returning prvalues, but that just puts the uncancellable
code inside of specific blocks. It still exists and still must be
uncancellable.
> In general, I would really like to use the handler mechanism you mentioned. I'll be sure to add the relevant part to the discussion, thank you.
> --
> Std-Proposals mailing list
> Std-Proposals_at_[hidden]
> https://lists.isocpp.org/mailman/listinfo.cgi/std-proposals
Received on 2023-07-15 13:40:47