How to stop Linux threads cleanly
mazzo.li
mazzo.li
I believe the author is mistaken here: throwing an exception that reaches the end of a noexcept block is not undefined behaviour; it will call std::terminate per [except.spec] [1].
The linked mailing list post [2] makes no mention of UB, only that this might cause exceptions to be thrown unbeknownst to the programmer in implicitly-noexcept blocks (i.e. destructors) which now might need a noexcept(false) to avoid std::terminate (although that’s still not great because throwing from a destructor will likely lead to resource leaks even if it’s handled).
And even if your don't want to do full-featured event loop and like synchronous style, it's pretty simple to add "poll" call to each network read (on just 2 descriptors: "termination pipe" and the FD you are interested in). Sure, it requires a custom wrapper for read/write/connect, but so is author's proposed signal-safe syscall.
You just need to make sure cancellable syscalls do not happen in destructors. (Which you probably want to do anyways, since cancellable syscalls can cause errors that are difficult to handle in destructors.)
Good practice is to move destructed objects to a "garbage collection" thread which calls the real destructors and cannot be cancelled.
Well, since thread cancellation is implemented using exceptions, and
thread cancellation can happen in arbitrary places, we’re always liable
to a cancellation happening in a noexcept block, which is undefined
behavior, and which in practice will cause your program to crash.
So since C++11, and especially since C++14 where destructors are marked
as noexcept by default, thread cancellation is essentially useless in C++Anyways, pthread_cancel can be of two types - asynchronous or deferred. Deferred is when cancellation happens only during a system call. It's the default and what you want. (You don't want the asynchronous mode.)
Under the hood thread cancellation is a C++ exception, so you still get RAII, etc.
(You probably want to do this regardless, because close() is not actually always an instanteneous syscall and can take a long time.)