[cpp-threads] Update on N2889/N2880/N2901
Anthony Williams
anthony at justsoftwaresolutions.co.uk
Mon Jun 22 08:56:40 BST 2009
It's Monday morning already here, but I know it's still Sunday for some
in the US, so I'll comment anyway.
Herb Sutter wrote:
> 1A: No detaching. Remove thread::detach from the standard. An
> argument against this is that Boost.Thread has thread::detach.
> Nevertheless, the feature is fundamentally flawed. Boost.Thread
> likewise has a thread::~thread with detach semantics, which has
> already been recognized is flawed in N2802 for similar reasons and
> was changed to terminate semantics in the WP at the Summit meeting.
Just because detached threads cannot reliably use global or static
objects during static destruction does not make them nearly useless.
That is grossly overstating the case. Many uses of detached threads will
be guaranteed to be completed before static destruction, because the
rest of the program relies on their side effects. In particular,
anything that uses manual synchronization such as condition variables,
futures or atomic values to identify when the thread has finished will
have defined behaviour.
This is particularly the case for programmers coming from a POSIX
threads background, where pthread_join is explicitly referred to as a
convenience function. For example, in Programming with POSIX Threads,
David Butenhof says "pthread_join is a convenience, not a rule" (p43 in
my copy).
Ruling out detached threads makes useful cases with custom
synchronization harder to write. I am strongly against removing detached
threads.
std::thread is supposed to be the lowest possible layer. If we want a
non-detachable, safer layer it should be built on top. We should not
restrict std::thread in order to make some use cases safer, at the cost
of making other useful cases much more expensive.
> 1B: Automatic joining. Require that the end of main automatically
> join with all still-running non-main threads before static
> destruction begins. An argument against this option is that some
> implementers want to write std::thread as a zero-overhead wrapper
> around another C-based API, such as pthreads. C-based APIs support
> detaching much more readily because they are designed for a language
> where shutdown is almost trivial: run atexit handlers then flush and
> close streams/files. However, discussion should address what the
> overhead actually is, especially considering that not joining will
> essentially result in undefined behavior.
Joining all threads before static destruction prevents globals starting
threads in their constructor and joining them in the destructor (perhaps
after setting a flag which will trigger the thread to end). This is a
useful scenario, particularly where the object in question is a thread
pool manager: it is typical for the pool threads to continue running
until the manager explicitly sets a flag indicating "no more work, stop
now". If we try and join the threads before the pool destructor has run
then the waiting thread will block forever as the pool hasn't told the
threads to shut down yet!
> 1C: Undefined behavior
> (punt). Require that a program must join with all non-main threads,
> including detached threads and heap-based new threads, before the end
> of main. Failing to do so is undefined behavior.
The issue here is how to identify when a program has "joined with" a
detached thread --- the thread is detached, so it must use a custom
mechanism. Again, it also rules out creating thread pools from global or
static objects.
I would prefer 1D (which I believe is already the case): Accessing an
object for which the destructor has already been called is undefined
behaviour.
It might be worth adding a note to make this clear in the context of
detached threads though.
> Incidentally, note also that thread_local objects with nontrivial
> destructors are a novelty. As mentioned in N2880, they are “new in
> C++0x, and not widely implemented.”
This is incorrect. The POSIX C API has destructor functions for
thread-specific values, and boost::thread_specific_ptr provides a
similar mechanism for C++ on many platforms (including Windows).
> (I believe someone else might be writing a
> paper for this same mailing to propose a thread state context for
> thread_local variables that accomplishes some but perhaps not all
> similar effects.)
That would be me. The paper is N2907, attached for reference.
> 2A: thread_local objects must have trivial destructors.
> This matches existing practice and eliminates the need for novel and
> problematic language destruction ordering rules. It would be
> desirable to also add a non-normative note showing one of the above
> recommended techniques to get a thread-local nontrivial object.
This is a backwards step cf existing practice. Non-trivial destructors
are also essential for anything that allocates resources (whether memory
or non-memory resources).
Anthony
--
Author of C++ Concurrency in Action | http://www.manning.com/williams
just::thread C++0x thread library | http://www.stdthread.co.uk
Just Software Solutions Ltd | http://www.justsoftwaresolutions.co.uk
15 Carrallack Mews, St Just, Cornwall, TR19 7UL, UK. Company No. 5478976
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://www.decadentplace.org.uk/pipermail/cpp-threads/attachments/20090622/ffef5f72/attachment-0001.html>
More information about the cpp-threads
mailing list