At the moment condition_variable::wait() is marked noexcept. It means that if pthread_cond_wait() acts as cancellation point and throws an exception the program is terminated with std::terminate(). This program demonstrates the issue: #include <condition_variable> #include <thread> int main() { std::mutex m; std::condition_variable cv; std::thread th([&] { std::unique_lock lock(m); cv.wait(lock); }); pthread_cancel(th.native_handle()); th.join(); } This program terminates with SIGABRT. Because of this using condition_variable::wait() in cancellable threads is tricky: the programmer has to guard all calls to condition_variable::wait() with disabling/restoring cancellation state. Also this stops the thread from being cancellable while in wait(). Therefore the outer thread has to know which condition_variable the thread waits and notify this condition_variable after pthread_cancel(). Also one should add cancellation point pthread_testcancel() immediately after restoring cancellation state after wait(). I believe it would be great if condition_variable::wait interacted nicer with POSIX-cancellation. I would like to suggest removing noexcept from condition_variable::wait(). This also matches the C++ standard very well [thread.condition.condvar] where condition_variable::wait() is not marked as noexcept.
Please note there was a related issue PR67726. I hope it is possible to meet the requirements mentioned in the issue as well as enabling cancellation.
(In reply to Ivan Sorokin from comment #0) > This also matches the C++ standard very well > [thread.condition.condvar] where condition_variable::wait() is not marked as > noexcept. Huh, I thought it was noexcept. Then yes, we should remove it. There are still lots of other places where the stadnard does require 'noexcept' and cancellation will terminate. NPTL thread cancellation via __forced_unwind just doesn't work well in C++.
> Huh, I thought it was noexcept. Then yes, we should remove it. Thank you very much! I'm looking forward for a fix. > There are still lots of other places where the stadnard does require 'noexcept' and cancellation will terminate. Do you have any specific functions in mind? If so perhaps something can be done about them too. Some people claim that noexcept and cancellation and mutually incompatible, but I don't think this is the case. I believe that by following a simple discipline noexcept and cancellation can interact very well. First of all not all noexcept functions are problematic: noexcept functions that don't call cancellation points are perfectly fine. The noexcept functions that do call some cancellation points can be fixed by suppression/restoring of cancellation. For example, a destructor that calls close() which is a cancellation point should just suppress/restore cancellation. Same for a destructor that calls pthread_join(). One might say that because of this we lose some cancellation points and this is true, but I believe that noexcept are the places where program can not recover preserving exception guarantees and having cancellation suppressed in these places is perfectly fine.
Yes, it's just a lot of work to implement correctly, and non-zero overhead to change the cancellation state.
The master branch has been updated by Jonathan Wakely <redi@gcc.gnu.org>: https://gcc.gnu.org/g:9e18a25331fa25c3907249fede65a02c6817b06e commit r12-5877-g9e18a25331fa25c3907249fede65a02c6817b06e Author: Jonathan Wakely <jwakely@redhat.com> Date: Tue Dec 7 15:11:15 2021 +0000 libstdc++: Allow std::condition_variable waits to be cancelled [PR103382] std::condition_variable::wait(unique_lock<mutex>&) is incorrectly marked noexcept, which means that the __forced_unwind exception used by NPTL cancellation will terminate the process. It should allow exceptions to pass through, so that a thread can be cleanly cancelled when waiting on a condition variable. The new behaviour is exported as a new version of the symbol, to avoid an ABI break for existing code linked to the non-throwing definition of the function. Code linked against older releases will have a reference to the @GLIBCXX_3.4.11 version, andcode compiled against the new libstdc++ will get a reference to the @@GLIBCXX_3.4.30 version. libstdc++-v3/ChangeLog: PR libstdc++/103382 * config/abi/pre/gnu.ver (GLIBCXX_3.4.11): Do not export old symbol if .symver renaming is supported. (GLIBCXX_3.4.30): Export new symbol if .symver renaming is supported. * doc/xml/manual/evolution.xml: Document change. * doc/html/manual/api.html: Regenerate. * include/bits/std_mutex.h (__condvar::wait, __condvar::wait_until): Remove noexcept. * include/std/condition_variable (condition_variable::wait): Likewise. * src/c++11/condition_variable.cc (condition_variable::wait): Likewise. * src/c++11/compatibility-condvar.cc (__nothrow_wait_cv::wait): Define nothrow wrapper around std::condition_variable::wait and export the old symbol as an alias to it. * testsuite/30_threads/condition_variable/members/103382.cc: New test.
The incorrect noexcept is fixed for GCC 12, but isn't suitable to backport. For the branches we should consider disabling cancellation as suggested in https://gcc.gnu.org/pipermail/gcc-patches/2021-December/586406.html
As the bug is fixed I'm closing the issue.
As I said in comment 6, we might want to disable cancellation in the release branches.