std::threadデストラクタ動作検討の歴史
N2184 Thread Launching for C++0X
The design of this thread is an evolution from boost::thread. The intent is to reuse as much of the boost::thread experience as possible, keeping the good, and changing the very minimum necessary to respond to the known limitations of this field experience.
- This proposal adds cancellation to the boost::thread, which is a significant complication. This change has a large impact not only on thread but the rest of the C++ threading library as well. It is believed this large change is justifiable because of the benefit.
- The thread destructor must now call cancel prior to detaching to avoid accidently leaking child threads when parent threads are canceled.
- An explicit detach member is now required to enable detaching without canceling.
N2320 Multi-threading Library for Standard C++
A significant complicating factor is the introduction of cancellation, and the de-facto differences between thread cancellation in C today, and the thread cancellation proposed for C++ in N2184.
N2447 Multi-threading Library for Standard C++
This is a revision of N2320 which removes cancellation/interruption and changes condition variables per the suggestions in N2406. This is the course of a action requested by the combined LWG/Concurrency working groups at the Kona meeting.
N2497 Multi-threading Library for Standard C++ (Revision 1)
If
joinable()
thendetach()
, otherwise no effects. [Note: Destroying ajoinable thread
can be unsafe if the thread accesses objects or the standard library unless the thread performs explicit synchronization to ensure that it does not access the objects or the standard library past their respective lifetimes. Terminating the process with_exit
orquick_exit
removes some of these obligations. -- end note]
N2802: A plea to reconsider detach-on-destruction for thread objects
Given the absence of a cancellation facility, acceptable options include:
- Joining the thread. This has the unfortunate consequence that throwing an exception will wait for threads being destroyed. But this is much more benign than stack overwrite errors by another thread. And if it results in serious responsiveness issues, e.g. because it creates deadlocks, it is debuggable. It does not risk security holes.
- Any specification that allows or requires the implementation to treat destruction of a joinable thread as an error. Lawrence Crowl suggested simply replacing the
detach()
call in the current specification with a call toterminate()
by analogy with unhandled exceptions. This is another error condition that cannot be safely reported via an exception.
→ N2802 (Alternative 2) adopted to C++11
N3630 async, ~future, and ~thread (Revision 1)
For similar reasons to the notes above, we are in the peculiar situation where
~thread
callsterminate
if not joined. That too is a problem, as noted for example in [2]
[...]
Instead, exactly one of the following should be true:
- (preferred) either
thread
owns the resource as an RAII type and therefore~thread
should join
implicitly;- or it is not and
~thread
should do nothing.We propose the former as this is consistent with the rest of the intent of the
thread
type, such as
movability.
N3636 ~thread Should Join
SG1 discussion of N3630 resulted in direction in favor of the proposal that
~thread
callsjoin
, not
terminate
, if the thread was not already joined.
This has no effect on programs that do not currently terminate. It just replaces the requirement to callterminate
with the requirement to instead calljoin
.Proposed Wording
Ifjoinable()
, callsjoin()
. Otherwise, has no effects. [Note: Because~thread
is required to be
noexcept
(17.6.5.12), ifjoin()
throws thenstd::terminate()
will be called. -- end note]
P020R60 Discussion about std::thread and RAII
C++ continues not to provide a thread type that would
join()
automatically on scope exit. This causes exception-safety problems, because failing tojoin()
in all code paths causes the destructor of astd::thread
toterminate()
.
- Solution 1: Change
std::thread::~thread
to auto-join- Solution 2: Add a new thread type that auto-joins
- Solution 3: Add a thread wrapper that auto-joins
P0206R1 A joining thread
Solution 2: Add a new thread type that auto-joins
In a large-group discussion in Jacksonville, the outcome was that a new thread type that joins in its destructor should be added. The benefit of this solution is that it's non-intrusive; all existing users ofstd::thread
are unaffected, for better or worse. Replacing the uses ofstd::thread
with the uses of the new type where need be is arguably straightforward.
P0660R0 A Cooperatively Interruptible Joining Thread
In Jacksonville 2016 we had an evening session P0206R0 with the following outcome:
[...]
Unfortunately, this decision was reverted later in Oulu in a smaller group so that we didn’t get what the majority voted for.
In addition, there are constantly requests to support interruption for started threads, which is implemented in Boost.Thread and was discussed but rejected during the standardization ofstd::thread
for C++11.
It’s time now to fulfill the need of an easy to use basic thread class for application programmers based on the experience of the existing Boost thread classes. Not providing this currently hinders projects to switch from Boost to the C++ standard library.
P0660R10 Stop Token and Joining Thread, Rev 10
This is the proposed wording for a cooperatively interruptible joining thread.
→ Adopted 2019-07 to C++20