Introduction

One of the major thrusts for C++0x is support for multi-threaded programs.
The Library Working Group has long agreed to provide basic library facilities
such as mutexes, condition variables, and threads based on the existing practice
of the Boost Threads library. This proposal provides the Working Paper text for
those components. Additional multi-threading components such as atomics and
futures are proposed elsewhere.

This proposal is the culmination of a long line of proposals. See
References.

The detailed discussion of motivations, rationales, design alternatives, and
other preliminary material remains unchanged from those proposals and is not
repeated in the current proposal.

This proposal assumes that exception propagation from threads will be handled
as described in
N2179
or its successors, and so is not included in this proposal.

At the meeting in Oxford, the committee asked Pete, Lawrence and Howard to combine
the C interface of
N1907
with
N2184
and produce a new proposal. This effort has only been partially successful. 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.

Pete produced
N2285
which is a faithful reproduction of the committee's request. However
N2285
lacks several of the advances in the mutex, lock and condition types which have emerged over
the years based on feedback from the boost experience
(N2094).
The rationale sections contained herein for these types go into more detail concerning
the differences between boost
(N1907,
N2285)
and the current proposal (which closely follows the previous
N2094).

An attempt was made to graft the style of the C interface in
N1907
onto the mutex types of
N2094.
It is felt that a key use case for the C level interface is to enable interoperability
between C and C++ translation units. An example use case from this early prototype
was:

The above example requires copying the C mutex types to the C++ mutex types
(or vice versa). Prior to this the mutex types have always been non-copyable.
The authors of this paper are not comfortable with copyable (or even movable)
mutex types.

condition::wait must be a C++ cancellation point. What happens when a
C translation unit is blocked in cnd_wait and a request to cancel comes in?
At this point in time we do not feel we can standardize propagating a C++ exception
through a C stack frame.

At this point the C/C++ interoperability design outlined in
N2145
for atomic types was brought to our attention. This approach neatly solves the first
problem above by making the C and C++ types layout compatible. The C and C++
translation units can both refer to the same structure, but operate on it with different
syntax and even different functions. This was prototyped and the above example use
case (for mutex only) simplified to:

Now mutex need not be moved, copied, or converted between C and C++ types.

However the second problem above (concerning cancellation) remained. To address this
issue this proposal initially stated that the C level interface of condition::wait
would return ECANCELED if it received a cancellation request. Now our example
interoperability use case looks like:

As indicated by the comment in the C function f, once C++ cancellation
is detected in a C translation unit, what is the C code supposed to do with it?

The C level interface has been removed from this proposal with the following
rationale:

As long as we specify that the key types in this proposal are
standard-layout types (which we have done), WG14 is still free to standardize
a C interface which interoperates with this C++ interface.

WG14 is in a better position to solve the cancellation interoperability
problem than WG21 is. We will specify that cancellation is nothing more than
a C++ exception. WG14 may in the future standardize a C++-compatible
try/finally which C cancellation can be built on. If this
happens we do
not want to have an existing C interface specified in the C++ standard which
specifies that C cancellation means returning ECANCELLED.

WG14 asked WG21 to take the lead on this issue. We feel we can best
take lead by specifying only a C++ interface which has the minimum hooks
in it to support a future C interoperating interface (i.e. types are
standard-layout types). We feel we should stop short of actually specifying
that C interface in the C++ standard. WG14 can do a better job with the
C interface and a future C++ standard can then import it by reference.

We would like to emphasize that despite the removal of the C interoperable interface
from this document, we continue to believe that C/C++ interoperability in this area
is important. We strongly encourage WG21 and WG14 cooperation in this area. We feel
that by specifying the standard layout for the mutex/condition/thread types we have
provided the necessary hooks for this interoperability. We would like to see the
technical guarantees surrounding this foundation firmed up. And we would like to see
prolific communication between WG21 and WG14 on this all important issue.

Thread

The thread class proposed herein follows closely to that as described in
N2184. This paper has the following differences:

cancel() has been renamed to request_cancellation() to better describe
the intent of this operation.

The classes thread and thread::id have been specified to have
standard layout to facilitate interoperability with a future C interface to be
specified by WG14.

The alias to join(), operator()() has been removed. It is expected
that future will have a member named join() to facilitate generic code
which can join either with threads or futures.

Joining with a thread

A std::thread can be joined with:

t.join(); // wait for thread t to end

One can test if a thread is joinable. If the thread
has already been joined with, or detached, then it is no longer joinable.
If the thread has been moved from, it is no longer joinable, unless
it has subsequently been moved back into.

If the above is not the desired behavior, the client of f can easily wrap
f in a functor using std::bind which catches unhandled exceptions
and performs some other action. For example here is such a functor which logs
unhandled exceptions, but does not otherwise indicate an error:

// threads can be stored in containers
int main()
{
std::vector<std::thread> thread_group;
thread_group.push_back(std::thread(f));
...
// Number of threads created here not known until run time
// (motivating the use of vector<thread> in this example)
...
// Join with all of the threads
for (auto i = thread_group.begin(), e = thread_group.end(); i != e; ++i)
i->join();
}

Thread ID

Despite the fact that std::thread is not copyable, its
idis copyable. Therefore clients can freely
pass around this id. But the only thing this information can
be used for is comparing the identity of threads. The id of a
thread can be obtained from a joinable std::thread.
Additionally a thread can obtain its own id without the use of
a std::thread (including the main thread). Finally an
id can be default constructed and is then guaranteed not to
compare equal to the id of any other running thread.

this_thread Namespace

Note the use of the this_thread namespace to disambiguate when you are requesting
the id for the current thread, vs the id of a child thread. The get_id
name for this action remains the same in the interest of reducing the conceptual footprint
of the interface. This design also applies to the cancellation_requested function:

The this_thread namespace also contains a few other functions that operate on, or query the
current thread of execution.

Canceling threads

A joinable std::thread can be cooperatively canceled. When
a thread cancels, all it does is throw an exception of type thread_canceled.
Thus a canceled thread can cancel its cancel simply by catching (and not re-throwing)
thread_canceled. One thread can request that another thread throw a
thread_canceled exception with this syntax:

To actually respond to a request to cancel, a thread must execute a
cancelation point. A thread can call cancellation_point() in order
to turn any code into a cancellation point.

std::this_thread::cancellation_point(); // Will throw a thread_canceled exception if
// and only if exceptions are enabled, and if
// someone has called t.request_cancellation() where t refers
// to this thread

Note that the main thread can not be canceled (by another thread) because cancellation
by another thread can only be done through a std::thread and there is no way
to create a std::thread which refers to the main thread.

A thread can disable cancellations for itself, even if it does execute a
cancellation point such as cancellation_point. This is done
with the disable_cancellation class. The construction of
this class has the effect of disabling cancellations for the lifetime of
the object. When the object destructs, cancellation is automatically
reverted to its previous state (typically re-enabled).

Because cancellation is disabled with a class object, the cancellation is guaranteed to
be correctly enabled whether the scope is left normally, or by an exception (whether or not
that exception is thread_canceled. Note: within this document, a convention is used that if the object
name is "_", that name is not used anywhere.

Cancellation is not disabled during stack unwinding. Destructors must be cancellation safe
whether they are being executed due to a thread_canceled exception, or any other
exception. Thus automatically disabling cancellation when a thread_canceled is
thrown is redundant. And there is at least one corner case where it causes ill effects.

disable_cancellation scopes can be nested. That is, outer code can disable
cancellation, and then call other functions, without fear that those functions will disable,
and subsequently enable cancellation prematurely.

If the main thread calls this_thread::cancellation_point() or
constructs an object of type
this_thread::disable_cancellation, there is no effect. The
main thread can not be canceled. Having these functions silently ignore
the main thread allows library code to use this functionality without
worry of whether it is being executed in the main thread or not.

One can request permission from a disable_cancellation object to temporarily
re-enable cancellation inside the scope. This requires a non-constdisable_cancellation
object:

The restore_cancellation constructor simply reverts to the cancellation state
that was in effect with the referenced disable_cancellation object was constructed.
Thus restore_cancellation doesn't actually enable cancellations unless the referenced
disable_cancellation was not constructed within the scope of another disable_cancellation.
Thus when a function says:

void bar()
{
std::this_thread::disable_cancellation _;
foo();
}

then it is not possible for code within the function foo to
enable cancellation (even if it tries to as with this example). To
enable cancellation in a called function, bar would have to
communicate the name of its disable_cancellation object to that
function.

This design has been set up to provide flexibility for disabling and enabling cancellation, yet
prevent accidental enabling when calling unknown code, and to prevent accidentally not re-enabling
when exceptions propagate through a stack frame.

Destructing a thread

Every thread must either be joined or detached within its
lifetime. To support cooperative cancellation, the thread destructor must
be prepared to deal with threads which have neither been joined
or detached. Consider for example a cancelable thread that owns
two child threads:

Upon cancellation of this thread (t1.join() is a cancellation point), a
thread_canceled exception propagates through the stack frame,
destructing t2 before it has had a chance to join. If
t2 simply detaches, then t2 may run for an
arbitrarily long time, and consume arbitrarily large resources. This
may result in the cancellation request of the parent thread
effectively not being honored. Thus when a thread is
destructed, if it is joinable then it is first
canceled, and then detached. This allows the parent
(canceling) thread to continue to cancel without blocking, and
yet notify all of its child threads of the cancellation
request.

If semantics other than request_cancellation(); detach(); are desired for a thread
destructor, this is easy to arrange for with a thread manager object. Such an
object would be a scope guard for a thread which points to the desired functionality
upon destruction. Smart pointers with policy destructors are easily and efficiently
employed as scope guards.

Threading cooperatively

Namespace this_thread has two functions for yielding processor control to
another thread:

Environment

There is one static member function of thread which yields a
measure of the number of threads which could possibly execute
concurrently:

unsigned n = std::thread::hardware_concurrency();

This can come in handy in a variety of situations such as sizing a thread pool.

Mutex

Mutex Rationale and Examples

Below is shown the basic operation of a mutex. Normally one will want to
lock and unlock mutexes using scoped_lock<mutex> or unique_lock<mutex>.
However lock, try_lock and unlock member functions are available in the mutex types themselves
to provide flexibility to the client.

Mutex concepts

Each of these three concepts have both recursive and non-recursive counterparts for a total of 6 concepts.

Mutex

RecursiveMutex

TryMutex

RecursiveTryMutex

TimedMutex

RecursiveTimedMutex

Because of anticipated support in the future for more mutex concepts (such as read/write) an attempt has
been made to reduce the number mutex concepts. It was noted that all mutex concepts can support the
TryMutex concept without extra expense. Therefore the TryMutex concept has been eliminated and folded
into the Mutex concept:

Mutex

RecursiveMutex

TimedMutex

RecursiveTimedMutex

It is shown later that the TryMutex concept is a necessary requirement for fundamental generic lock
algorithms such as std::lock(L1&, L2&, L3&...) and is thus a good idea to include
as a fundamental requirement for all mutex types (high benefit, zero cost).

Time Issues

Most of the time-related interface is based on time durations (e.g. milliseconds(100))
instead of specific points in time (eg: 2007-May-28 00:00:00.12345). The one exception to this policy
is the timed_wait member of the condition variable. In this case spurious wake ups are expected,
and when this happens, without timing against a specific point in time, it is difficult to know
whether you've woken up for spurious reasons or because of a time out, and if for spurious reasons
how much longer you need to wait for. Therefore timed_wait on condition variables alone is
specified in terms of a specific point in time. Every effort has been made to anticipate the
TR2 date_time support and make the standard interface compatible with that. See
N2328 for details.

Lock Rationale and Examples

Unlike boost locks, the locks proposed herein are not nested types of the mutex classes
but class templates which are templated on the mutex type. The locks thus become far more
reusable. They can be instantiated with any standard or user-defined mutex which meets
the mutex requirements.

The purpose of scoped_lock is to serve the common use case with as
much efficiency as possible. Unlike the boost scoped_lock, this
scoped_lock always owns its referenced mutex. There need be no
internal flag indicating ownership. The scoped_lock destructor
does not need to perform a test to see if it should unlock the mutex: it
unconditionally unlocks the mutex. Thus there is no branch which might stall
a processor pipeline just to unlock the mutex.

Using a scoped_lock also easily signals intent: The referenced mutex
is locked and unlocked strictly within the containing scope. There is no need
for the reader of the code to search for places where mutex ownership might be
transferred out of the current scope.

It is not possible to have a scoped_lock that does not refer to a mutex.
And it is not possible for that referenced mutex to not be locked by the
scoped_lock. The only way to lock the mutex is with the scoped_lock
constructor, and the only way to unlock it is with the scoped_lock destructor.
This is far more restrictive than the boost scoped_lock, but slightly more
efficient as well. Because of the prevalence of the scoped locking pattern, it is
felt by the authors that a maximally efficient lock dedicated to this use case is
justified.

Because there exist use cases which require more flexibility than a
strict scoped style locking pattern, unique_lock is introduced.
Unlike scoped_lock, unique_lock may or may not
reference a mutex, and if it does, may or may not own the locked state
of that mutex. This is much more like the semantics of the boost
scoped_lock. However, unlike the boost scoped_lock,
unique_lock services all of the mutex concepts (timed and
non-timed). A unique_lock is movable, but not copyable,
so they can be put into containers and returned from factory functions.

In the example above, unique_lock serves to provide exception
safety, unlocking lock1 if the attempt to lock lock2
throws an exception. However, because strict scoped locking isn't desired in
this use case, the unique_lock is asked to release its lock
ownership if both lock1 and lock2 are successfully
locked.

Also note in the above example that L1 and L2 may
also be unique_lock types. Because of the generality of the
templated locks (as opposed to being available only as nested types
of a mutex), the try_lock algorithm can easily and seamlessly
create a unique_lock<unique_lock<Mutex>> type
(ul in the example if L1 is a unique_lock<Mutex>).

Finally note a few syntactic differences between boost scoped_lock and
unique_lock which lead to improved readability:

try_to_lock is used to indicate try_lock on construction
instead of a bool.

boost scoped_lock::locked() has been renamed to owns().
Rationale: This member may return false and that does not mean that the referenced
mutex is not locked. It means that thisunique_lock does not own
the locked state of the mutex. The mutex may still be locked (say by another thread).

Looking forward, TR2 may have a new lock type that does not model exclusive ownership as
scoped_lock and unique_lock do, but rather models shared ownership.
A reasonable name for such a lock might be shared_lock.

template <class Mutex> scoped_lock; // Scoped, exclusive ownership

template <class Mutex> unique_lock; // Exclusive ownership

template <class Mutex> shared_lock; // Shared ownership

We feel that the above is an appropriate naming convention for the various lock types.

Generic Locking Algorithm Rationale and Examples

Consider a user written class which contains a data member mutex which controls access
to the object:

Unfortunately the above code is wrong and can lead to deadlock. Given two
objects of type Record, r1 and r2, if one
thread executes r1 = r2 while at the same time another thread
executes r2 = r1, then it is possible to deadlock. For example:

unique_lock is now required instead of scoped_lock as one can not
defer the locking of the mutex within a scoped_lock. Note too that the locks
locked with std::lock do not need to be the same type. So if we have read/write
locking in the future this might look like:

In the above example this is write-locked and r is read-locked,
all done in a deadlock-safe manner.

Condition Variables

Condition variables are a inter-thread notification mechanism which work closely
with mutexes and locks. The typical use case is for a thread to lock a mutex (or lock)
associated with some data which is used to compute a predicate (e.g. does the queue have items).
When the predicate is false, the thread will wait on the condition variable using the still
locked mutex as an argument to the wait function. The locked mutex assures that no other thread
can change the protected data while the current thread-of-execution is in the process of blocking (waiting) for that
data to be updated. Once the waiting thread is blocked, the system unlocks the mutex so that
another thread can lock the mutex, update the protected data, unlock the mutex, and signal
the condition variable to wake one or more threads to process the protected data.

The example above demonstrates basic condition usage. The condition type: condition_ulm
is a typedef for condition<unique_lock<mutex>> (the ulm is
an acronym for unique_lock<mutex>). thread1 acts as
a consumer, waiting until there is data in the queue to process. The queue is checked, and
data is removed from the queue under the protection of a std::mutex which is locked
with a std::unique_lock. While thread1 waits for the empty queue to have
data pushed into it, the system unlocks the mutex.

thread2 in the above example supplies data to the queue. As it is accesses the shared
data queue it protects it with the std::mutex. When thread2 detects that the
queue has transitioned from empty to one element, it signals thread1 via the
condition variable. If thread1 isn't blocked on the condition variable at this
time, the notification is harmlessly ignored.

Both thread1 and thread2 do as much processing as possible with the std::mutex
unlocked, thus increasing overall throughput.

Condition Variable Flexibility

A template class condition<Lock> is supplied, where the only requirements
on Lock are that it support lock() and unlock() member functions.
Lock could be any of the standard mutexes or locks, or any user defined mutex or lock
(as long as they meet the lock/unlock requirements.

Assuming that TR2 brings read/write mutexes and shared locks, they will be usable with this
std::condition. Being able to wait with a read/write mutex, locked either for
reading or writing, goes significantly beyond Posix capabilities and Boost capabilities
(though Windows Vista has this capability).

This pattern might allow a single producer, needing a write lock, to signal many consumers
which need only read locks to "consume", which finally might signal a single clean up thread
needing a write lock to dispose of the data.

Some functions
described in this clause are specified to throw exceptions of type system_error
([syserr.syserr]). The error_category ([syserr.errcat.overview])
of the error_code reported by such exceptions code()
member function is implementation-defined. [Note: The category is
typically native_category ([syserr.errcat.overview]) since these error
codes usually originate from the underlying operating system application program
interface (API). -- end note]

Remarks: The message may be a null-terminated multibyte string
([multibyte.strings]), suitable for conversion and display as a wstring
([string.classes], [locale.codecvt]). The return value remains valid until the exception
object from which it is obtained is destroyed or a non-const member
function of the exception object is called.

Class thread

An object of class thread launches a new thread-of-execution,
and provides mechanisms for the current thread-of-execution to wait for
completion of the launched thread, request cooperative cancellation of the
launched thread, and perform other operations to manage and query the thread's
state.

Remarks:get_id() returns an identity that refers to
not any thread. This identity compares equal to other
non-joinable threads, and compares not equal to all
other joinable threads.

Throws: Nothing.

template <class F> explicit thread(F f)

Requires: If f is an lvalue, F must be CopyConstructible.
If f is an rvalue, F must only be MoveConstructible.

Effects: Constructs an object of type thread and executes the
functor f asynchronously as a new thread-of-execution. F is a functor which takes
no argument. Any return value from the functor is ignored. If f terminates with an
uncaught exception of type thread_canceled, or of type publicly derived from thread_canceled,
then the effect shall be as if f returned normally. If f terminates with an uncaught
exception of any other type, std::terminate() shall be called.

Postconditions:

get_id() != thread::id()
&& joinable() == true

For the newly created thread-of-execution, this_thread::cancellation_enabled()
is true. [Note: cancellation is enabled upon thread creation.
-- end note]

*this represents the newly started thread-of-execution.

Throws:system_error if unable to start this thread.

~thread()

Effects: If joinable() then request_cancellation() followed by detach(),
otherwise no effects.

Throws: Nothing.

thread(thread&& x)

Effects: Constructs an object of type thread from x.

Postconditions:x.joinable() is false.
x.get_id() == thread().get_id(). joinable()
returns the value of x.joinable() prior to the start of
construction.
get_id() returns the value of x.get_id() prior to the
start ofconstruction.

Throws: Nothing.

thread& operator=(thread&& x)

Effects: If this currently refers to a joinable thread, calls
request_cancellation() and detach(). Then assigns the state of x to *this
and sets x to a default constructed state.

Postconditions:x.joinable() is false.
x.get_id() == thread().get_id(). joinable() returns the
value of x.joinable() prior to the
assignment.
get_id() returns the value of x.get_id() prior to the
assignment.

Throws: Nothing.

void swap(thread&& x)

Effects: Swaps the state of *this and x.

Throws: Nothing.

void request_cancellation()

Preconditions:joinable() is true.

Postcondition:cancellation_requested() is true.

Throws: Nothing.

bool cancellation_requested() const

Preconditions:joinable() is true.

Returns: For the thread-of-execution represented by *this,
this_thread::cancellation_requested().

Throws: Nothing.

bool joinable() const

Returns:get_id() != id().

Throws: Nothing.

void join()

Preconditions:joinable() is true.

Effects: The current thread-of-execution blocks until the thread-of-execution
represented by *this completes.

Postconditions: After a normal return of join(),
joinable() is false. An exceptional return will indicate that
the thread-of-execution represented by *this has received a request to
cancel. In such an event, the thread-of-execution represented by
*this remains unaffected.

Throws: If, for the thread-of-execution represented by
*this, this_thread::cancellation_requested() becomes
true during the call to join(), throws thread_canceled.

Remarks: This function is a cancellation point for the current
thread-of-execution. [Note: The
main thread can not be canceled even at a cancellation point. --end note]

Effects: The current thread-of-execution blocks until the the
thread-of-execution represented by
*this completes,
or until the indicated time duration expires.

Postconditions: If timed_join returns true,
joinable() shall be false. An exceptional return will indicate
that the current thread-of-execution has received a request to
cancel. In such an event, the the thread-of-execution represented by
*this remains unaffected.

Returns:true if the thread-of-execution represented by
*this joined, otherwise false.

Throws: If, for the thread-of-execution represented by
*this, this_thread::cancellation_requested() becomes
true during the call to join(), throws thread_canceled.

Remarks: This function is a cancellation point for the current
thread-of-execution. [Note: The
main thread can not be canceled even at a cancellation point. --end note]

void detach()

Preconditions:joinable() is true.

Effects: The thread-of-execution represented by
*this continues execution. When the thread-of-execution represented by
*this ends execution it shall release any owned resources.

Postconditions:joinable() is false. *this
does not represent a thread-of-execution.

Throws: Nothing.

thread::id()

Effects: Constructs an object of type thread::id which compares
equal to other default constructed thread::id objects.

Throws: Nothing.

bool operator==(const id& x, const id& y)

Returns: If x and y both represent
not any thread, then returns true. Otherwise if
x and y represent the same thread-of-execution, then
returns true. Otherwise returns false.

Throws: Nothing.

bool operator!=(const id& x, const id& y)

Returns:!(x == y)

Throws: Nothing.

bool operator<(const thread_id& x, const thread_id& y)

Returns: Provides an ordering for all objects of type thread_id, such that
objects of type thread_id can be used as a key in Associate Containers.
For two objects of type thread_id,
x and y, if
x == y returns true, both x < y and y < x shall return
false. Otherwise, precisely one of x < y and y < x shall return
true.

Throws: Nothing.

bool operator<=(const thread_id& x, const thread_id& y)

Returns:!(y < x)

Throws: Nothing.

bool operator>(const thread_id& x, const thread_id& y)

Returns:y < x

Throws: Nothing.

bool operator>=(const thread_id& x, const thread_id& y)

Returns:!(x < y)

Throws: Nothing.

id get_id() const

Returns: A thread::id which refers to the thread-of-execution
represented by
*this. If this
thread is not joinable() returns a default constructed id.

Returns: The number of threads that can reasonably be expected to
execute concurrently. [Note: This value should only be considered to be a hint.
--end note] If this value is not computable or well defined a
return value of 1 is recommended, but not required.

Effects: Constructs an object of type disable_cancellation. The construction
has the effect of disabling requests to cancel the current thread-of-execution from other threads during the
lifetime of this object (except as modified by restore_cancellation). When a cancellation
point is executed within the lifetime of this object, a request to cancel has no affect (except
as modified by restore_cancellation). The constructor also notes the current cancellation
state so that it can be restored at the time this object is destructed.

Throws: Nothing.

Postconditions:this_thread::cancellation_enabled() returns false.

Remarks: This function has no effect if executed from the main thread.

~disable_cancellation()

Effects: Restores the enable-cancellation state to the same as it was when this
disable_cancellation was constructed.

Throws: Nothing.

Remarks: This function has no effect if executed from the main thread.

Effects: If cancellation_enabled() && cancellation_requested() then
throws an exception of type thread_canceled, else there is no effect.

Postconditions: If a thread_canceled is thrown, then cancellation_requested()
shall be false.

Throws:thread_canceled.

bool cancellation_enabled()

Returns: If this is the main thread, returns false.
Otherwise returns true unless a disable_cancellation object
has been constructed (and not destructed) and which has not been reverted
with a restore_cancellation object.

Throws: Nothing.

bool cancellation_requested()

Returns:true if request_cancellation() has been called on this
thread and the thread has not yet executed a cancellation point with cancellation
enabled.

Throws: Nothing.

thread::id this_thread::get_id()

Returns: Returns the id of the current thread. The return shall not be
equal to a default constructed thread::id.

Throws: Nothing.

void yield()

Effects: Offers the operating system the chance to schedule another thread.

Throws: Nothing.

template <class ElapsedTime>
void sleep(const ElapsedTime& rel_t)

Requires:ElapsedTime shall be explicitly convertible to nanoseconds.

Effects: The current thread-of-execution blocks for at least the amount of time specified, unless
it receives a request to cancel.

Throws: Nothing.

Remarks: This function is a cancellation point.

struct once_flag

Objects of class once_flag are opaque data structures that allow
call_once to initialize data without causing a data race or
deadlock.

constexpr once_flag();

Effects: Constructs a object of type
once_flag.

Postcondition: Internal state is set to indicate to an invocation
of call_once with this once_flag as its initial
argument that no function has been called.

non-member function call_once

Requires: If the Callable argument func is an lvalue, F
is
CopyConstructible. Otherwise, func is an rvalue,
and F is
MoveConstructible. Copying or moving (as appropriate) shall have no side effects, and the effect of calling the
copy shall be equivalent to calling the original.

Effects: The argument func (or a copy thereof) is called exactly once
for the once_flag object specified by flag, as-if by invoking
func(args),even if call_once is
called multiple times for the same once_flag object. If multiple
calls to call_once with the same once_flag object
occur in separate threads-of-execution, only one
thread shall call func, and none of the threads shall proceed until the call to func has completed.
If the invocation of func results in an exception being thrown,
the exception is propagated to the caller and the effects are as-if this
invocation of call_once did not occur.

Throws:system_error or any exception propagated from func.

Thread safety: Access to the same once_flag object by
calls to call_once from different threads-of-execution shall
not result in a data race or deadlock.

Mutex concepts

Objects of the mutex types enforce mutual exclusion between threads-of-execution
by limiting ownership of a mutex object to a single thread-of-execution. A
thread-of-execution gets ownership of a mutex object by calling lock() and
relinquishes ownership by calling unlock(). Ownership can not
be transferred from one thread-of-execution to another. The same
thread-of-execution that calls
lock() for a mutex object must call unlock() for the object. Mutexes can be either recursive
or non-recursive. The syntax is the same for both recursive and non-recursive
mutexes, but the semantics for the member functions differs as described below.

Each mutex type shall be default constructible and destructible. If the default construction
of the Mutex type fails, an exception of type system_error shall be thrown. The destructor
of the Mutex type shall not throw an exception.
Mutex types are neither copyable
nor movable. Each mutex type shall have the following member functions:

void lock();

Precondition: For non-recursive mutexes the current thread-of-execution shall not own the mutex.

Effects: The current thread-of-execution will block until the mutex is not owned by another thread-of-execution.
Upon successful completion, the current thread-of-execution owns the mutex.

Throws:system_error.

Thread safety: Calls from different threads-of-execution to lock, try_lock,
and unlock functions on an object of a mutex type shall not result in data races or deadlocks.

bool try_lock();

Precondition: For non-recursive mutexes the current thread-of-execution shall not own the mutex.

Effects: If ownership can be obtained without blocking, then ownership is obtained,
else there is no effect and try_lock() immediately returns.

Returns:true if ownership was obtained, otherwise false.

Thread safety: Calls from different threads-of-execution to lock, try_lock,
and unlock functions on an object of a mutex type shall not result in data races or deadlocks.

Throws: Nothing.

void unlock();

Precondition: The current thread-of-execution shall own the mutex.

Effects: For a non-recursive mutex ownership is released. For a recursive mutex
unlock() must be called the same number of times which the mutex was locked
(via either lock() or try_lock() or by any other locking function) before ownership is released.

Thread safety: Calls from different threads-of-execution to lock,
and try_lock functions on an object of a mutex type shall not result in data races or deadlocks.

Throws: Nothing.

If and only if the mutex type is internally represented by a single data structure
which can be passed to operating system specific interfaces, then there shall be a nested
implementation-defined typedef native_handle_type that is an alias to this native type if it is copyable,
otherwise if the native type is not copyable, is a pointer to this native type.
The implementation shall document whether or not the native_handle_type
typedef is present.

If the nested typedef native_handle_type exists, then there
also shall be a member function native_handle() which returns a handle
to this internal data structure. [Example:

If there is no single operating system specific data structure which implements
the mutex type, then neither the nested type native_handle_type nor the
member function native_handle() shall not be present. [Example:
if a recursive_mutex is implemented with both a pthread_mutex_t
and a separate lock count, then there will be no native_handle_type.
--end example]

Implementations may supply additional implementation defined constructors
which allow further customization as afforded by the implementation
or its environment.

Class static_mutex

The class static_mutex is based on a new language feature constexpr
which is not yet in the working draft, nor do we have field experience with it. Should
this language feature fail to deliver the static initialization behavior desired, we
recommend removing static_mutex from the working paper.

The class static_mutex is a non-recursive mutex. It shall be a standard-layout type ([?]),
and does not require dynamic initialization. The default constructor,
if dynamically initialized, shall not throw an exception.

Precondition: For non-recursive mutexes the current thread-of-execution shall not own the mutex.
The type ElapsedTime shall be explicitly convertible to nanoseconds.

Effects: The function attempts to obtain ownership of the mutex within the specified time.
If the indicated time is less than or equal to 0, the function still attempts to obtain ownership without
blocking (as if by calling try_lock()). If the function returns within the specified
time duration, it shall have obtained ownership.

Returns:true if ownership was obtained, otherwise false.

Thread safety: Calls to this member function from different
threads-of-execution shall not result in data races or deadlocks.

The class recursive_timed_mutex shall be a recursive mutex that satisfies all of the Timed Mutex requirements.
It shall be a standard-layout type ([?]).

Locks

Locks are objects that hold a reference to a mutex and unlock the mutex during the lock's destruction
(such as when leaving block scope). The locks do not manage the lifetime of the mutex they
reference, but only the ownership status of that mutex. [Note: Locks are intended to ease the burden
of unlocking the mutex under both normal and exceptional circumstances. --end
note]

Some locks may take tag types which describe what should be done with the mutex in the lock's
constructor.

An exception class lock_error derives from exception and is used to indicate
improper usage of locks such as locking a mutex that the lock already owns, or unlocking a mutex
that the lock does not own.

scoped_lock is used to control the ownership of a mutex within a single scope.
An invariant of the scoped_lock object is that it maintains the ownership of the
mutex throughout the scoped_lock's lifetime. Mutex ownership can not be deferred
or transferred away from the scoped_lock.

explicit scoped_lock(mutex_type& m);

Precondition: If mutex_type is not a recursive mutex, the current thread-of-execution
does not own the mutex. The lifetime of m is greater than the lifetime
of the scoped_lock object.

Effects: Stores a reference to m and calls m.lock().

scoped_lock(mutex_type& m, accept_ownership_type);

Precondition: The current thread-of-execution has ownership of the mutex m.
The lifetime of m is greater than the lifetime of the
scoped_lock object.

Effects: Stores a reference to m and performs no other operation on it.

unique_lock is used to control the ownership of a mutex within one or more scopes.
Mutex ownership can be deferred or transferred away from the unique_lock.
An object of type
unique_lock is not copyable but is movable.

unique_lock();

Effects: Constructs an object of type unique_lock.

Postcondition:

mutex() == 0
owns() == false

explicit unique_lock(mutex_type& m);

Precondition: If mutex_type is not a recursive mutex, the current thread-of-execution
does not own the mutex. The lifetime of m is greater than the lifetime
of the unique_lock object.

Effects: Stores a reference to m and calls m.lock().

Postcondition:

mutex() == &m
owns() == true

unique_lock(mutex_type& m, defer_lock_type);

Precondition: If mutex_type is not a recursive mutex, the current thread-of-execution
does not own the mutex.
The lifetime of m is greater than the lifetime of the
unique_lock object.

Effects: Stores a reference to m and performs no other operation on it.

Postcondition:

mutex() == &m
owns() == false

unique_lock(mutex_type& m, try_lock_type);

Precondition: If mutex_type is not a recursive mutex, then the current thread-of-execution
does not own the mutex.
The lifetime of m is greater than the lifetime of the
unique_lock object.

Effects: Stores a reference to m and calls m.try_lock().

Postcondition:

mutex() == &m
owns() == The result of the call tom.try_lock()

unique_lock(mutex_type& m, accept_ownership_type);

Precondition: The current thread-of-execution has ownership of the mutex m.
The lifetime of m is greater than the lifetime of the
unique_lock object.

Effects: Stores a reference to m and performs no other operation on it.

Postcondition:

mutex() == &m
owns() == true

~unique_lock();

Effects: If owns() calls unlock() on the referenced mutex.
Otherwise there are no effects.

Throws: Nothing.

unique_lock(unique_lock&& u);

Effects: Transfers mutex ownership (if any) from u to this.

Postcondition:

mutex() == The value of u.mutex() prior to the construction.
owns() == The value of u.owns() prior to the construction.
u.mutex() == 0
u.owns() == false

Throws: Nothing.

unique_lock& operator=(unique_lock&& u);

Effects: If owns() calls unlock(), and then
transfers mutex ownership (if any) from u to this.

Postcondition:

mutex() == The value of u.mutex() prior to the construction.
owns() == The value of u.owns() prior to the construction.
u.mutex() == 0
u.owns() == false

Throws: Nothing.

Note: With a recursive mutex it is possible that both
this and u own the same mutex before the assignment.
In this case, this will own the mutex after the assignment (and
u will not), but the mutex's lock count will be decremented by
one.

void lock();

Effects: Calls lock() on the referenced mutex.

Postcondition:owns() == true.

Throws:lock_error, if on entry owns() is true.

bool try_lock();

Effects: Calls try_lock() on the referenced mutex.

Returns: The result of the call to try_lock() on the referenced mutex.

Postcondition:owns() == The result of the call to try_lock() on the referenced mutex.

Generic Locking Algorithms

Requires: Each template parameter type must supply the following member functions with semantics
corresponding to the Mutex concept, except that try_lock is allowed to throw an
exception. [Note: The unique_lock class template meets these requirements
when suitable instantiated. --end note]

bool try_lock();
void unlock();

Effects: The functions attempts to lock all arguments without blocking by calling try_lock()
on each of them. If any argument can not be locked, then all arguments which have already been locked will
be unlocked. On return, either all arguments will be locked, or none of them will be locked. If an
exception is thrown by a call to try_lock(), there are no effects.

Requires: Each template parameter type must supply the following member functions with semantics
corresponding to the Mutex concept, except that try_lock is allowed to
throw an exception [Note: The unique_lock class template meets these requirements
when suitable instantiated. --end note]

void lock();
bool try_lock();
void unlock();

Effects: All arguments are locked with an algorithm that avoids deadlock.
If an exception is thrown by a call to lock() or try_lock(), there are no effects.

Class template condition

An object of class template condition is a synchronization primitive
used to cause a thread-of-execution to wait until notified by some other
thread-of-execution that some condition is met, or a UTC[(?)] time is reached.

The Lock type must support member functions lock
and unlock with the semantics of the mutex concept. All of the standard mutex types
meet this requirement. Additionally Lock may provide an owns() signature
returning bool as outlined for the unique_lock class template. If present,
the condition class template will use this member for error checking.

Effects: If any threads-of-execution are blocked waiting for *this,
unblocks at least one those threads.

Thread safety: Calls to the wait,
timed_wait, notify_one or
notify_all member functions of the same condition
object from different threads-of-execution shall not result in data
races or deadlocks.

void notify_all();

Effects: Unblock all threads that are blocked waiting for *this.

Thread safety: Calls to the wait,
timed_wait, notify_one or
notify_all member functions of the same condition
object from different threads-of-execution shall not result in data
races or deadlocks.

void wait(lock_type& lock);

Precondition:lock is locked by the current thread-of-execution. If
lock_type supports recursive locking, the lock count is one. No
other thread-of-execution is waiting on this condition object unless lock
is, or refers to, the same underlying mutex object.

Effects: Atomically blocks and releases the lock
on lock. If the thread-of-execution is canceled while blocked, lock
will be locked as the thread_canceled exception propagates out. This
thread-of-execution shall unblock when another thread issues a notification to this blocked thread. The current thread-of-execution may unblock and return even in the absence
of a notification.

Postcondition:lock is locked by the current
thread-of-execution.

Throws:thread_canceled, system_error. If
lock_type has an owns() member function and
lock.owns() returns false upon entry, a lock_error is
thrown.

Thread safety: Calls to the wait,
timed_wait, notify_one or
notify_all member functions of the same condition
object from different threads-of-execution shall not result in data
races or deadlocks.

Remarks: This function is a cancellation point for the calling thread. [Note: The
main thread can not be canceled even at a cancellation point. --end note]

Precondition: The lock is locked by the current thread-of-execution. If
lock_type supports recursive locking, the lock count is one. No
other thread-of-execution is waiting on this condition object unless lock
is, or refers to, the same underlying mutex object.

Effects: Atomically blocks and releases the lock
on lock. If the thread-of-execution is canceled while blocked, lock
will be locked as the thread_canceled exception propagates out. If the
absolute time specified by abs_time passes (that is, system time
equals or exceeds abs_time) before the condition is
notified, or if the absolute time specified by abs_time has already been
passed at the time of the call, then false is returned. This
thread-of-execution shall unblock when another thread issues a notification to this blocked thread. The current thread-of-execution may unblock and return even in the absence
of a notification.

Postcondition:lock is locked by the current
thread-of-execution.

Returns:true if the call to timed_wait is notified prior
to the indicated timeout,
otherwise returns false.

Throws:thread_canceled, system_error. If
lock_type has an owns() member function and
lock.owns() returns false upon entry, a lock_error is
thrown.

Thread safety: Calls to the wait,
timed_wait, notify_one or
notify_all member functions of the same condition
object from different threads-of-execution shall not result in data
races or deadlocks.

Remarks: This function is a cancellation point for the calling thread. [Note: The
main thread can not be canceled even at a cancellation point. --end note]

Note: There is no blocking if pred() is initially true, even
if the timeout has already expired. The return value indicates whether the predicate
evaluates to true, regardless of whether the timeout was triggered.

The specialization condition<mutex> shall be a standard-layout type ([?]).

Acknowledgments

The overall design of this threading library is based on William Kempf's
Boost.Thread Library, as refined by literally hundreds of other Boost users and
contributors. Dinkumware and Metrowerks (now Freescale) implementations of
Boost.Thread, developed respectively by Pete Becker and Howard Hinnant, created
further existing practice. Proposals by Pete Becker, Peter Dimov, Ion Gaztañaga,
and Anthony Williams were also influential. Peter, Ion, and Anthony also
contributed numerous critiques, suggestions, and comments on the current
proposal, as did other members of an ad hoc threads working group.