Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is there any movement towards specifying interaction of C++ exceptions and pthread cancellation?

The GNU C library uses DWARF2 unwinding for pthread cancellation these days, so that both C++ exceptions and pthread cancellation cleanup handlers get called through a common call frame unwinding process which invokes destructors for automatic objects as necessary along the way. However, as far as I can tell there is still no standard that specifies the interaction between (POSIX) threads and C++, and presumably an application wishing to be portable should assume that throwing exceptions out of cancellation cleanup contexts is just as undefined as calling longjmp out of them, and that cancelling a thread that has live automatic objects with non-trivial destructors is also undefined behavior.

Is there any standardization process in progress that addresses this interaction, or is it something that can be expected to be undefined well into the future? Does C++11 have any analogous notion to POSIX thread cancellation in its thread support?

like image 494
R.. GitHub STOP HELPING ICE Avatar asked Feb 25 '12 00:02

R.. GitHub STOP HELPING ICE


1 Answers

As someone who sits on ISO/IEC SC22 which encompasses WG14 (C), WG15 (POSIX) and WG21 (C++), I can tell you that the quick answer is no, C++ exceptions and thread cancellation are not going to see one another any time soon. C11 and C++11 make no mention of thread cancellation, and are highly if not extremely unlikely to recognise it before the next major standards release in about ten years time.

The longer answer comes down to how standards work. Basically ISO can only standardise what everyone can come to agree upon, and people do not agree when it comes to thread cancellation. The whole idea of a thread of execution having to dump state before every cancellable system call goes against the whole ethos of modern software development. It causes immense problems for compiler optimisation because unlike C++ exception throws, a thread cancel is defined to be the same as calling thread_terminate(self) which explicitly precludes doing anything additional (and even cancellation handlers aren't reliably called on many implementations), and I don't think that the thread cancellation supporters would disagree it's a bad solution.

The problem is that the only proper alternative is to reissue the POSIX i/o API with async completion variants. And the problem with that is that different POSIX implementations think of async completion very differently. I mean, we can't even agree on a standard for kernel wait queues, so until that can be achieved an async i/o API is a long way off. I have a proposal to make some movement on kernel wait queues for the next standards TC/TR, but the proposed object is deliberately extremely simplistic.

What we've tried to do in C11/C++11 is for the threading API to always have non-blocking versions - there is only one API in there which can't be done non-blocking which is thread_join() (there is no thread_timedjoin()) and I plan to personally submit an errata on that after I have Austin Working Group approval. In all other cases, one can always construct something which polls which isn't efficient, but is program correct.

In the longer run, personally speaking I see plenty of good reason to add exception handling to C following similar semantics to C++. You wouldn't have object support necessarily (I would actually support adding non-virtual objects to C too personally), but you would have the concept of stack unwound lambda function calls. That would let us formalise hacks like thread cancellation with a properly defined mechanism. It also makes writing fault tolerant C much easier and safer by letting you write the unwind as you write the wind, and lets old C transparently interop with new C.

Regarding throwing exceptions from within exception handling, me personally I think we need to do something better than just always auto invoking terminate(). As unwinding may cause the construction of new objects, or indeed any other source of exception throws, I personally would greatly prefer if every reasonable attempt is made to unwind the whole stack before terminating the process.

So, in short, expect POSIX thread cancellation to continue to be viewed as undefined, and the strong chances are in the long run it'll get deprecated in favour of something better.

BTW, generally POSIX thread cancellation is highly unportable between implementations, so any code which uses POSIX thread cancellation is effectively relying on platform-specific behaviour which is identical to using non-POSIX APIs. If you want your code to be portable, don't use POSIX thread cancellation. Instead use select() or poll() including a magic "please stop thread now" file descriptor. In my own C++ code, I actually have a system API wrapper macro which tests for this magic file descriptor and throws a special C++ exception. This ensures identical behaviour on all platforms, including Windows.

like image 179
Niall Douglas Avatar answered Sep 30 '22 13:09

Niall Douglas