ISO/IEC JTC1 SC22 WG21 N2497=08-0007 - 2008-01-07
Lead author: Howard E. Hinnant
Major contributors: Lawrence Crowl, Beman Dawes, Anthony Williams, Jeff Garland
Other contributors: Hans Boehm, Nick Stoughton, Chris Kohlhoff, PremAnand M Rao, Nathan Myers, Dietmar Kühl, Alisdair Meredith
Introduction
Chapter 17 Library introduction [library]
17.1.? blocked thread [defns.thread.blocked]
17.1.? deadlock [defns.deadlock]
Chapter 20 General utilities library [utilities]
20.5 Function objects [function.objects]
20.5.15 Class template hash
[unord.hash]
Chapter 30 Multi-threading library [thread]
30.1 Common Issues [thread.common]
30.1.1 Template Parameter Names [thread.tmplparmname]
30.1.2 Exceptions [thread.exception]
30.1.3 Native Handles [thread.native]
30.1.4 Timing Specifications [thread.timing_specifications]
30.2 Threads [thread.threads]
30.2.1 Class thread [thread.threads.class]
30.2.1.1 Class thread::id
[thread.threads.id]
30.2.1.2 thread
constructors [thread.threads.constr]
30.2.1.3 thread
destructor [thread.threads.destr]
30.2.1.4 thread
assignment [thread.threads.assign]
30.2.1.5 thread
members [thread.threads.member]
30.2.1.6 thread
static members [thread.threads.static]
30.2.1.7 thread
specialized algorithms [thread.threads.algorithm]
30.2.2 Namespace this_thread
[thread.threads.this]
30.3 Mutual Exclusion [thread.mutex]
30.3.1 Mutex requirements [thread.mutex.requirements]
30.3.1.1 Class mutex [thread.mutex.class]
30.3.1.2 Class recursive_mutex [thread.mutex.recursive]
30.3.2 TimedMutex requirements [thread.timedmutex.requirements]
30.3.2.1 Class timed_mutex [thread.timed.class]
30.3.2.2 Class recursive_timed_mutex [thread.timed.recursive]
30.3.3 Locks [thread.lock.intro]
30.3.3.1 Class lock_guard [thread.lock.guard]
30.3.3.2 Class unique_lock [thread.lock.unique]
30.3.4 Generic Locking Algorithms [thread.lock.algorithm]
30.3.5 Call Once [thread.mutex.once]
30.3.5.1 struct once_flag
[thread.mutex.onceflag]
30.3.5.2 non-member function call_once
[thread.threads.callonce]
30.4 Condition variables [thread.condition]
30.4.1 Class condition_variable [thread.condvar]
30.4.2 Class condition_variable_any [thread.condvarany]
Chapter 31 Date Time Library [time]
31.1 Duration requirements [time.duration.requirements]
31.2 Class nanoseconds [time.nanoseconds]
31.3 Class microseconds [time.microseconds]
31.4 Class milliseconds [time.milliseconds]
31.5 Class seconds [time.seconds]
31.6 Class minutes [time.minutes]
31.7 Class hours [time.hours]
31.8 Class system_time [time.system]
31.9 Non-member functions [time.nonmembers]
References
Acknowledgments
This paper is a revision of N2447. It incorporates following changes:
call_once
moved
from <thread>
to <mutex>
.
thread F
constructor
split in two for efficiency reasons.
thread::id
clarified.
native_handle
description consolidated to one place.
unique_lock
timed-constructors added
to match timed-member functions.
wait
/timed_wait
clarified.
This paper uses the following conventions in the HTML source to ease conversion into the format of the working paper.
Add the following definitions:
a thread that is waiting for some condition (other than the availability of a processor) to be satisfied before it can continue execution. [Footnote: This definition is taken from POSIX. —end footnote] As a verb, to block is to place a thread in the blocked state, and to unblock is to place a thread in the unblocked state.
two or more threads are unable to continue execution because each is blocked waiting for one or more of the others to satisfy some condition.
Modify paragraph 2 as follows:
Header
functional
synopsisnamespace std { ... // Hash function specializations ... struct hash<std::thread::id>; }
hash
[unord.hash]Modify paragraph 1 as follows:
The unordered associative containers defined in clause 23.4 use specializations of
hash
as the default hash function. This class template is only required to be instantiable for integer types (3.9.1), floating point types (3.9.1), pointer types (8.3.1), andstd::string
,std::u16string
,std::u32string
,std::wstring
,andstd::error_code
, andstd::thread::id
.
The following subclauses describe components to create and manage threads ([intro.multithread]), perform mutual exclusion, and communicate conditions between threads.
Subclause | Header(s) |
---|---|
Threads | <thread> |
Mutual Exclusion | <mutex> |
Condition variables | <condition_variable> |
Unless otherwise stated, the thread-safety requirements of 17.4.3.? ([constraints.?]) and 17.4.4.9 ([res.on.thread.safety]) [Editor: as proposed by N2410 Thread-Safety in the Standard Library (Rev 1) —end editor] apply even to types and functions within this clause.
Throughout this clause, the names of template parameters are used to express type requirements.
The requirements for Duration parameters are specified in chapter 31 [time].
If a parameter is Predicate, operator()
applied to the actual template argument
shall return a value that is convertible
to bool
.
Implementations of functions described in this clause are permitted to call
operating system or other low-level applications program interfaces (API's).
Some functions
described in this clause
are specified to throw exceptions of type system_error
([syserr.syserr]).
Such exceptions shall be thrown if such a call results in an error that
prevents the library function from satisfying its postconditions or from
returning a meaningful value.
The error_category
([syserr.errcat.overview])
of the error_code
reported by such an exception's code()
member function is implementation-defined.
[Note:
The category is
typically system_category
([syserr.errcat.overview])
since these error
codes usually originate from
the underlying operating system application program
interface (API).
—end note]
Several classes described in this clause have members
native_handle_type
and native_handle
.
The presence of these
members and their semantics is implementation defined.
[Note:
These
members allow implementations to provide access to implementation details.
Their
names are specified to facilitate portable compile-time detection.
Actual use of
these members is inherently non-portable.
—end note]
Several functions described in this clause take an argument to specify a timeout. These timeouts are specified as either a Duration or a Time Point type as specified in [time].
The resolution of timing provided by an implementation depends on both operating system and hardware. The finest resolution provided by an implementation is called the native resolution.
This section describes components to create and manage threads.
[Note: These threads are intended to map one-to-one with operating system threads. —end note]
<thread> synopsis
namespace std { class thread; void swap(thread& x, thread& y); void swap(thread&& x, thread& y); void swap(thread& x, thread&& y); namespace this_thread { thread::id get_id(); void yield(); void sleep(const system_time& abs_t); template <class Duration> void sleep(const Duration& rel_t); } // this_thread } // std
The class thread
provides a mechanism
to create a new thread of execution,
and to join with a thread
(i.e. wait for a thread to complete),
and to perform other operations
that manage and query the state of the thread.
A thread
object uniquely represents
a particular thread of execution.
That representation may be transferred to other thread objects
in such a way that no two thread
objects simultaneously
represent the same thread of execution.
A thread of execution is detached
when no thread
object represents that thread.
Objects of class thread
can be in a state
that does not represent a thread of execution.
[Note:
A thread
object
does not represent a thread of execution after default construction,
after being moved from,
or after a successful call to detach
or join
.
—end note]
class thread { public: // types: class id; typedef implementation-defined native_handle_type; // See [thread.native] // construct/copy/destroy: thread(); template <class F> explicit thread(F f); template <class F, class ...Args> thread(F&& f, Args&&... args); ~thread(); thread(const thread&) = delete; thread(thread&&); thread& operator=(const thread&) = delete; thread& operator=(thread&&); // members: void swap(thread&&); bool joinable() const; void join(); void detach(); id get_id() const; native_handle_type native_handle(); // See [thread.native] // static members: static unsigned hardware_concurrency(); };
Class thread
and class thread::id
shall be standard-layout
classes (chapter 9 [class]).
thread::id
[thread.threads.id]class thread::id { public: id(); }; bool operator==(thread::id x, thread::id y); bool operator!=(thread::id x, thread::id y); bool operator<(thread::id x, thread::id y); bool operator<=(thread::id x, thread::id y); bool operator>(thread::id x, thread::id y); bool operator>=(thread::id x, thread::id y); template<class charT, class traits> basic_ostream<charT, traits>& operator<< (basic_ostream<charT, traits>&& out, thread::id id);
An object of type thread::id
provides
a unique identifier for each thread of execution
and a single distinct value for all thread objects
that do not represent a thread of execution ([thread.threads.class]).
Each thread of execution has a thread::id
that is not equal to the thread::id
of other threads of execution
and that is not equal to
the thread::id
of std::thread
objects
that do not represent threads of execution.
[Note:
Relational operators allows thread::id
objects
to be used as keys in associative containers.
—end note]
id();
- Effects:
- Constructs an object of type
id
.- Throws:
- Nothing.
- Postconditions:
- The constructed object does not represent a thread.
bool operator==(thread::id x, thread::id y);
- Returns:
- Returns
true
only ifx
andy
represent the same thread of execution or neitherx
nory
represent a thread of execution.- Throws:
- Nothing.
bool operator!=(thread::id x, thread::id y);
- Returns:
!(x == y)
- Throws:
- Nothing.
bool operator<(thread::id x, thread::id y);
- Returns:
- A value such that
operator<
is a total ordering as described in [alg.sorting].- Throws:
- Nothing.
bool operator<=(thread::id x, thread::id y);
- Returns:
!(y < x)
- Throws:
- Nothing.
bool operator>(thread::id x, thread::id y);
- Returns:
y < x
- Throws:
- Nothing.
bool operator>=(thread::id x, thread::id y);
- Returns:
!(x < y)
- Throws:
- Nothing.
template<class charT, class traits>
basic_ostream<charT, traits>&
operator<< (basic_ostream<charT, traits>&& out, thread::id id);
- Effects:
- Inserts an unspecified text representation of the
thread::id
into the streamout
. Distinct thread id's shall have distinct representations.- Returns:
out
.
thread
constructors [thread.threads.constr]
thread();
- Effects:
- Constructs a
thread
object that does not represent a thread of execution.- Postconditions:
get_id() == id()
.- Throws:
- Nothing.
template <class F> explicit thread(F f);
template <class F, class ...Args> thread(F&& f, Args&&... args);
- Requires:
F
and eachTi
inArgs
shall beCopyConstructible
if an lvalue and otherwiseMoveConstructible
.INVOKE(f, w1, w2, ..., wN)
([func.require]) shall be a valid expression for some valuesw1, w2, ..., wN
, whereN == sizeof...(Args)
.- Effects:
- Constructs an object of type
thread
and executesINVOKE(f, t1, t2, ..., tN)
in a new thread, wheret1, t2, ..., tN
are the values inargs...
. Any return value fromf
is ignored. Iff
terminates with an uncaught exception,std::terminate()
shall be called.- Synchronization:
The invocation of the constructor happens before ([intro.multithread]) the invocation of
f
.Every thread shall ensure that all its uses of static-duration variables happen before ([intro.multithread ]) their destruction and that all calls to the standard library happen before ([intro.multithread]) completion of destruction of static-duration variables and execution of
std::atexit
registered functions ([support.start.term]). [Note: Terminating the thread before a call tostd::exit
or the exit frommain
is sufficient, but not necessary, to satisfy this requirement. This requirement permits thread managers as static-duration objects. —end note]- Postconditions:
get_id() != id()
.*this
represents the newly started thread.- Throws:
system_error
orbad_alloc
if unable to start the new thread.
thread(thread&& x);
- Effects:
- Constructs an object of type
thread
fromx
, and setsx
to a default constructed state.- Postconditions:
x.get_id() == id()
andget_id()
returns the value ofx.get_id()
prior to the start of construction.- Throws:
- Nothing.
thread
destructor [thread.threads.destr]
~thread();
- Effects:
- 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]- Throws:
- Nothing.
thread
assignment [thread.threads.assign]
thread& operator=(thread&& x);
- Effects:
- If
joinable()
, callsdetach()
. Then assigns the state ofx
to*this
and setsx
to a default constructed state.- Postconditions:
x.get_id() == id()
, andget_id()
returns the value ofx.get_id()
prior to the assignment.- Throws:
- Nothing.
thread
members [thread.threads.member]
void swap(thread&& x);
- Effects:
- Swaps the state of
*this
andx
.- Throws:
- Nothing.
bool joinable() const;
- Returns:
get_id() != id()
.- Throws:
- Nothing.
void join();
- Precondition:
joinable()
istrue
.- Synchronization:
- The completion of the thread represented by
*this
happens before ([intro.multithread])join()
returns. [Note: Operations on*this
are not synchronized. —end note]- Postconditions:
- If
join()
throws an exception, the value returned byget_id()
remains unchanged. Otherwiseget_id() == id()
.- Throws:
system_error
when the postconditions cannot be achieved.
void detach();
- Precondition:
joinable()
istrue
.- Effects:
- The thread represented by
*this
continues execution without the current thread blocking. Whendetach()
returns,*this
no longer represents the possibly continuing thread of execution. When the thread represented by*this
ends execution, the implementation shall release any owned resources.- Postconditions:
get_id() == id()
.- Throws:
system_error
when the effects or postconditions cannot be achieved.
id get_id() const;
- Returns:
- A default constructed
id
if*this
does not represent a thread, otherwisethis_thread::get_id()
for the thread of execution represented by*this
.- Throws:
- Nothing.
thread
static members [thread.threads.static]
unsigned hardware_concurrency();
- Returns:
- The number of hardware thread contexts. [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 0 is recommended, but not required.
- Throws:
- Nothing.
thread
specialized algorithms [thread.threads.algorithm]
void swap(thread& x, thread& y);
void swap(thread&& x, thread& y);
void swap(thread& x, thread&& y);
- Effects:
x.swap(y)
.
this_thread
[thread.threads.this]namespace this_thread { thread::id get_id(); void yield(); void sleep(const system_time& abs_t); template <class Duration> void sleep(const Duration& rel_t); } // this_thread
thread::id this_thread::get_id();
- Returns:
- An object of type
thread::id
that uniquely identifies the current thread of execution. No other thread of execution shall have this id and this thread of execution shall always have this id. The object returned shall not compare equal to a default constructedthread::id
.- Throws:
- Nothing.
void yield();
- Effects:
- Offers the operating system the opportunity to schedule another thread.
- Synchronization:
- None.
- Throws:
- Nothing.
void sleep(const system_time& abs_t);
- Effects:
- The current thread blocks at least until the time specified.
- Synchronization:
- None.
- Throws:
- Nothing.
template <class Duration>
void sleep(const Duration& rel_t);
- Effects:
- The current thread blocks for at least the amount of time specified. If the resolution of
Duration
is finer than the native resolution, the time is rounded to the next larger value that can be represented in the native resolution.- Synchronization:
- None.
- Throws:
- Nothing.
This section provides mechanisms for mutual exclusion: mutexes, locks, and call once. These mechanisms ease the production of race-free programs ([intro.multithread]).
<mutex> synopsis
namespace std { class mutex; class recursive_mutex; class timed_mutex; class recursive_timed_mutex; struct defer_lock_t; struct try_to_lock_t; struct adopt_lock_t; extern const defer_lock_t defer_lock; extern const try_to_lock_t try_to_lock; extern const adopt_lock_t adopt_lock; class lock_error; template <class Mutex> class lock_guard; template <class Mutex> class unique_lock; template <class Mutex> void swap(unique_lock<Mutex>& x, unique_lock<Mutex>& y); template <class Mutex> void swap(unique_lock<Mutex>&& x, unique_lock<Mutex>& y); template <class Mutex> void swap(unique_lock<Mutex>& x, unique_lock<Mutex>&& y); template <class L1, class L2, class ...L3> int try_lock(L1&, L2&, L3&...); template <class L1, class L2, class ...L3> void lock(L1&, L2&, L3&...); struct once_flag { constexpr once_flag(); once_flag(const once_flag&) = delete; once_flag& operator=(const once_flag&) = delete; }; template<class Callable, class ...Args> void call_once(once_flag& flag, Callable func, Args&&... args); } // std
A mutex object facilitates protection against data races
and allows thread-safe synchronization of data between threads.
A thread owns a mutex from the time it successfully calls one of the
lock functions until it calls unlock
.
Mutexes may be either recursive or non-recursive,
and may grant simultaneous ownership to one or many threads.
The mutex types supplied by the Standard Library
provide exclusive ownership semantics:
only one thread may own the mutex at a time.
Both recursive and non-recursive mutexes are supplied.
This section describes requirements on template argument types
used to instantiate templates defined in the C++ Standard Library.
The template definitions in the C++ Standard Library
refer to the named Mutex requirements
whose details are set out below.
In this description, m
is an object of a mutex type.
A mutex type
shall be DefaultConstructible
and Destructible
.
If initialization of a mutex type fails,
an exception of type system_error
shall be thrown.
A mutex type is neither copyable nor movable.
The implementation will provide lock and unlock operations, as described below. The implementation shall serialize those operations. [Note: Construction and destruction of a mutex type need not be thread-safe; other synchronization must be used to ensure that mutexes are initialized and visible to other threads. —end note]
The expression m.lock()
shall be well-formed,
and have the following semantics:
- Effects:
- The current thread will block until ownership of the mutex can be obtained for the current thread.
- Postconditions:
- The current thread owns the mutex.
- Return type:
void
- Synchronization:
- Prior
unlock()
operations on the same object synchronize with ([intro.multithread]) this operation.- Throws:
system_error
when the effects or postconditions cannot be achieved.
The expression m.try_lock()
shall be well-formed,
and have the following semantics:
- Effects:
- Attempt to obtain ownership of the mutex for the current thread without blocking. If ownership is not obtained, there is no effect and
try_lock()
immediately returns. An implementation may fail to obtain the lock even if it is not held by any other thread. [Note: This spurious failure is normally uncommon, but allows interesting implementations based on a simplecompare_swap
([atomics.operations]). —end note]- Return type:
bool
- Returns:
- If ownership of the mutex was obtained for the current thread,
true
, otherwise,false
.- Synchronization:
- If
try_lock
returnstrue
, priorunlock()
operations on the same object synchronize with ([intro.multithread]) this operation. [Note: Sincelock()
does not synchronize with a failed subsequenttry_lock()
, the visibility rules are weak enough that little would be known about the state after a failure, even in the absence of spurious failures. —end note]- Throws:
- Nothing.
The expression m.unlock()
shall be well-formed,
and have the following semantics:
- Precondition:
- The current thread shall own the mutex.
- Effects:
- Releases the current thread's ownership of the mutex.
- Return type:
void
- Synchronization:
- This operation synchronizes with ([intro.multithread]) subsequent lock operations that obtain ownership on the same object.
- Throws:
- Nothing.
namespace std { class mutex { public: mutex(); ~mutex(); mutex(const mutex&) = delete; mutex& operator=(const mutex&) = delete; void lock(); bool try_lock(); void unlock(); typedef implemenation-defined native_handle_type; // See [thread.native] native_handle_type native_handle(); // See [thread.native] }; } // std
The class mutex
provides a non-recursive mutex with exclusive ownership semantics.
If one thread owns the mutex
object, attempts by another thread to
acquire ownership will fail (for try_lock()
) or block (for
lock()
) until the first thread has released ownership with a call to
unlock()
.
It satisfies all the Mutex requirements ([thread.mutex.requirements]). It shall be a standard-layout class ([class]).
The behavior of a program is undefined:
lock()
or try_lock()
and the
thread
already owns the mutex
object.
mutex
object.
mutex
object owned by any thread.
namespace std { class recursive_mutex { public: recursive_mutex(); ~recursive_mutex(); recursive_mutex(const recursive_mutex&) = delete; recursive_mutex& operator=(const recursive_mutex&) = delete; void lock(); bool try_lock(); void unlock(); typedef implemenation-defined native_handle_type; // See [thread.native] native_handle_type native_handle(); // See [thread.native] }; } // std
The class recursive_mutex
provides a recursive mutex with exclusive ownership semantics.
If one thread owns the recursive_mutex
object, attempts by another
thread to acquire ownership will fail (for try_lock()
) or block
(for lock()
) until the first thread has completely released
ownership.
It satisfies all the Mutex requirements ([thread.mutex.requirements]). It shall be a standard-layout class ([class]).
A thread that owns a recursive_mutex
object
may acquire additional levels of ownership
by calling lock()
or try_lock()
.
It is unspecified how many levels of ownership
may be acquired by a single thread.
If a thread has already acquired the maximum level of ownership
for a recursive_mutex
object,
additional calls to try_lock()
shall fail,
and additional calls to lock()
shall throw an exception
of type system_error
.
A thread must call unlock()
once
for each level of ownership acquired by calls
to lock()
and try_lock()
.
Only when all levels of ownership have been released
may ownership be acquired by another thread.
The behavior of a program is undefined:
recursive_mutex
object.
recursive_mutex
object owned by any thread.
To meet the TimedMutex requirements,
types shall meet the Mutex requirements.
In addition, the following requirements shall be met,
where rel_time
denotes a value of a type meeting the Duration ([time.duration]) requirements
or abs_time
denotes a value of type system_time
:
The expression m.timed_lock(rel_time)
shall be well-formed,
and have the following semantics:
- Precondition:
- If the resolution of
Duration
is finer than the native resolution, the time is rounded up to the nearest native resolution.- Effects:
- The function attempts to obtain ownership of the mutex within the
rel_time
time duration. If therel_time
time duration is less than or equal to0
, the function attempts to obtain ownership without blocking (as if by callingtry_lock()
). The function shall return within therel_time
time duration only if is has obtained ownership of the mutex object. [Note: As withtry_lock()
, there is no guarantee that ownership will be obtained if the lock is available, but implementations are expected to make a strong effort to do so. —end note]- Return type:
bool
- Returns:
true
if ownership was obtained, otherwisefalse
.- Synchronization:
- If
timed_lock
returnstrue
, priorunlock()
operations on the same object synchronize with ([intro.multithread]) this operation.- Throws:
- Nothing.
The expression m.timed_lock(abs_time)
shall be well-formed,
and have the following semantics:
- Effects:
- The function attempts to obtain ownership of the mutex by the
abs_time
absolute time. Ifabs_time
has already passed, the function attempts to obtain ownership without blocking (as if by callingtry_lock()
). The function shall return by theabs_time
absolute time only if is has obtained ownership of the mutex object. [Note: As withtry_lock()
, there is no guarantee that ownership will be obtained if the lock is available, but implementations are expected to make a strong effort to do so. —end note]- Return type:
bool
- Returns:
true
if ownership was obtained, otherwisefalse
.- Synchronization:
- If
timed_lock
returnstrue
, priorunlock()
operations on the same object synchronize with ([intro.multithread]) this operation.- Throws:
- Nothing.
namespace std { class timed_mutex { public: timed_mutex(); ~timed_mutex(); timed_mutex(const timed_mutex&) = delete; timed_mutex& operator=(const timed_mutex&) = delete; void lock(); bool try_lock(); template <class Duration> bool timed_lock(const Duration& rel_time); bool timed_lock(const system_time& abs_time); void unlock(); typedef implemenation-defined native_handle_type; // See [thread.native] native_handle_type native_handle(); // See [thread.native] }; } // std
The class timed_mutex
provides a non-recursive mutex with exclusive ownership semantics.
If one thread owns the timed_mutex
object,
attempts by another thread to acquire ownership
will fail (for try_lock()
)
or block (for lock()
and timed_lock()
)
until the first thread has released ownership with a call to
unlock()
,
or the call to timed_lock()
times out
(having failed to obtain ownership).
It satisfies all of the TimedMutex requirements ([thread.timedmutex.requirements]). It shall be a standard-layout class (chapter 9 [class]).
The behavior of a program is undefined:
lock()
,
try_lock()
or either overload of timed_lock
and the
thread already owns the timed_mutex
object.
timed_mutex
object.
timed_mutex
object owned by any thread.
namespace std { class recursive_timed_mutex { public: recursive_timed_mutex(); ~recursive_timed_mutex(); recursive_timed_mutex(const recursive_timed_mutex&) = delete; recursive_timed_mutex& operator=(const recursive_timed_mutex&) = delete; void lock(); bool try_lock(); template <class Duration> bool timed_lock(const Duration& rel_time); bool timed_lock(const system_time& abs_time); void unlock(); typedef implemenation-defined native_handle_type; // See [thread.native] native_handle_type native_handle(); // See [thread.native] }; } // std
The class recursive_timed_mutex
provides a recursive mutex with exclusive ownership semantics.
If one thread owns the recursive_timed_mutex
object,
attempts by another thread to acquire ownership
will fail (for try_lock()
)
or block (for lock()
or timed_lock()
)
until the first thread has completely released ownership,
or the call to timed_lock()
times out
(having failed to obtain ownership).
It satisfies all of the TimedMutex requirements ([thread.timedmutex.requirements]). It shall be a standard-layout class (chapter 9 [class]).
A thread that owns a recursive_timed_mutex
object
may acquire additional levels of ownership
by calling lock()
, try_lock()
or timed_lock()
.
It is unspecified how many levels of ownership
may be acquired by a single thread.
If a thread has already acquired the maximum level of ownership
for a recursive_timed_mutex
object,
additional calls to try_lock()
or timed_lock()
shall fail,
and additional calls to lock()
shall throw an exception
of type system_error
.
A thread must call unlock()
once
for each level of ownership acquired by calls
to lock()
, try_lock()
and timed_lock()
.
Only when all levels of ownership have been released
may ownership be acquired by another thread.
The behavior of a program is undefined:
recursive_timed_mutex
object.
recursive_timed_mutex
object
owned by any thread.
A lock is an object that holds a reference to a mutex and may unlock the mutex during the lock's destruction (such as when leaving block scope). A thread of execution may use a lock to aid in managing mutex ownership in an exception safe manner. A lock is said to own a mutex if it is currently managing the mutex ownership for a thread of execution. 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 lock constructors may take tag types, which describe what should be done with the mutex during the lock's construction.
struct defer_lock_t {}; // do not acquire ownership of the mutex struct try_to_lock_t {}; // try to acquire ownership of the mutex // without blocking struct adopt_lock_t {}; // assume the current thread has already // obtained mutex ownership and manage it extern const defer_lock_t defer_lock; extern const try_to_lock_t try_to_lock; extern const adopt_lock_t adopt_lock;
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.
class lock_error : public std::exception { public: virtual const char* what() const throw(); };
namespace std { template <class Mutex> class lock_guard { public: typedef Mutex mutex_type; explicit lock_guard(mutex_type& m); lock_guard(mutex_type& m, adopt_lock_t); ~lock_guard(); lock_guard(lock_guard const&) = delete; lock_guard& operator=(lock_guard const&) = delete; private: mutex_type& pm; // for exposition only }; } // std
An object of type
lock_guard
controls the ownership of a mutex within a scope.
A lock_guard
object maintains ownership of a mutex
throughout the lock_guard
's lifetime.
The behavior of a program is undefined
if the mutex referenced by pm
does not exist for the entire lifetime ([basic.life])
of the lock_guard
object.
explicit lock_guard(mutex_type& m);
- Precondition:
- If
mutex_type
is not a recursive mutex, the current thread does not own mutexm
.- Effects:
m.lock()
.- Postconditions:
&pm == &m
.
lock_guard(mutex_type& m, adopt_lock_t);
- Precondition:
- The current thread owns mutex
m
.- Postconditions:
&pm == &m
.- Throws:
- Nothing.
~lock_guard();
- Effects:
pm.unlock()
.- Throws:
- Nothing.
namespace std { template <class Mutex> class unique_lock { public: typedef Mutex mutex_type; unique_lock(); explicit unique_lock(mutex_type& m); unique_lock(mutex_type& m, defer_lock_t); unique_lock(mutex_type& m, try_to_lock_t); unique_lock(mutex_type& m, adopt_lock_t); unique_lock(mutex_type& m, const system_time& abs_time); template <class Duration> unique_lock(mutex_type& m, const Duration& rel_time); ~unique_lock(); unique_lock(unique_lock const&) = delete; unique_lock& operator=(unique_lock const&) = delete; unique_lock(unique_lock&& u); unique_lock& operator=(unique_lock&& u); void lock(); bool try_lock(); template <class Duration> bool timed_lock(const Duration& rel_t); bool timed_lock(const system_time& abs_time); void unlock(); bool owns_lock() const; explicit operator bool () const; mutex_type* mutex() const; void swap(unique_lock&& u); mutex_type* release(); private: mutex_type* pm; // for exposition only bool owns; // for exposition only }; template <class Mutex> void swap(unique_lock<Mutex>& x, unique_lock<Mutex>& y); template <class Mutex> void swap(unique_lock<Mutex>&& x, unique_lock<Mutex>& y); template <class Mutex> void swap(unique_lock<Mutex>& x, unique_lock<Mutex>&& y); } // std
An object of type
unique_lock
controls the ownership of a mutex within a scope.
Mutex ownership
may be acquired at construction or subsequent to construction,
and subsequent to acquisition
may be transferred to another unique_lock
object.
Objects of type unique_lock
are not copyable but are movable.
The behavior of a program is undefined
if mutex() != 0
and the mutex pointed to by mutex()
does not exist for the entire remaining lifetime ([basic.life])
of the unique_lock
object.
unique_lock();
- Effects:
- Constructs an object of type
unique_lock
.- Postconditions:
pm == 0
owns == false
- Throws:
- Nothing.
explicit unique_lock(mutex_type& m);
- Precondition:
- If
mutex_type
is not a recursive mutex, the current thread does not own the mutex.- Effects:
- Constructs an object of type
unique_lock
, callsm.lock()
.- Postconditions:
pm == &m
owns == true
unique_lock(mutex_type& m, defer_lock_t);
- Precondition:
- If
mutex_type
is not a recursive mutex, the current thread does not own the mutex.- Effects:
- Constructs an object of type
unique_lock
.- Postconditions:
pm == &m
owns == false
- Throws:
- Nothing.
unique_lock(mutex_type& m, try_to_lock_t);
- Precondition:
- If
mutex_type
is not a recursive mutex, then the current thread does not own the mutex.- Effects:
- Constructs an object of type
unique_lock
, callsm.try_lock()
.- Postconditions:
pm == &m
owns ==
the result of the call tom.try_lock()
- Throws:
- Nothing.
unique_lock(mutex_type& m, adopt_lock_t);
- Precondition:
- The current thread owns mutex
m
.- Effects:
- Constructs an object of type
unique_lock
.- Postconditions:
pm == &m
owns == true
- Throws:
- Nothing.
unique_lock(mutex_type& m, const system_time& abs_time);
- Precondition:
- If
mutex_type
is not a recursive mutex, then the current thread does not own the mutex.- Effects:
- Constructs an object of type
unique_lock
and callsm.timed_lock(abs_time)
.- Postconditions:
pm == &m
owns ==
the result of the call tom.timed_lock(abs_time)
- Throws:
- Nothing.
template <class Duration>
unique_lock(mutex_type& m, const Duration& rel_time);
- Remarks:
- The implementation shall ensure that only
Duration
types ([time]) will bind to this constructor.
- Precondition:
- If
mutex_type
is not a recursive mutex, then the current thread does not own the mutex.- Effects:
- Constructs an object of type
unique_lock
and callsm.timed_lock(rel_time)
.- Postconditions:
pm == &m
owns ==
the result of the call tom.timed_lock(rel_time)
- Throws:
- Nothing.
~unique_lock();
- Effects:
- If
owns
callspm->unlock()
.- Throws:
- Nothing.
unique_lock(unique_lock&& u);
- Postconditions:
pm ==
the value ofu.pm
prior to establishment of postconditions onu
.
owns ==
the value ofu.owns
prior to establishment of postconditions onu
.
u.pm == 0
u.owns == false
- Throws:
- Nothing.
unique_lock& operator=(unique_lock&& u);
- Effects:
- If
owns
callspm->unlock()
.- Postconditions:
pm ==
the value ofu.pm
prior to establishment of postconditions onu
.
owns ==
the value ofu.owns
prior to establishment of postconditions onu
.
u.pm == 0
u.owns == false
- Throws:
- Nothing.
[Note: With a recursive mutex it is possible that both
*this
andu
own the same mutex before the assignment. In this case,*this
will own the mutex after the assignment (andu
will not). —end note]
void lock();
- Effects:
pm->lock()
.- Postconditions:
owns == true
- Throws:
lock_error
, if on entryowns
istrue
or ifpm == 0
.
bool try_lock();
- Effects:
pm->try_lock()
.- Returns:
- The result of the call to
try_lock()
.- Postconditions:
owns ==
the result of the call totry_lock()
.- Throws:
lock_error
, if on entryowns
istrue
or ifpm == 0
.
template <class Duration>
bool timed_lock(const Duration& rel_t);
- Effects:
pm->timed_lock(rel_t)
.- Returns:
- The result of the call to
timed_lock(rel_t)
.- Postconditions:
owns ==
the result of the call totimed_lock(rel_t)
.- Throws:
lock_error
, if on entryowns
istrue
or ifpm == 0
.
bool timed_lock(const system_time& abs_t);
- Effects:
pm->timed_lock(abs_t)
.- Returns:
- The result of the call to
timed_lock(rel_t)
.- Postconditions:
owns ==
the result of the call totimed_lock(rel_t)
.- Throws:
lock_error
, if on entryowns
istrue
or ifpm == 0
.
void unlock();
- Effects:
pm->unlock()
.- Postconditions:
owns == false
- Throws:
lock_error
, if on entryowns
isfalse
.
bool owns_lock() const;
- Returns:
owns
.- Throws:
- Nothing.
explicit operator bool () const;
- Returns:
owns
.- Throws:
- Nothing.
mutex_type* mutex() const;
- Returns:
pm
.- Throws:
- Nothing.
void swap(unique_lock&& u);
- Effects:
- Swaps each data member of
*this
with the equivalent data member ofu
.- Throws:
- Nothing.
mutex_type* release();
- Returns:
- The previous value of
pm
.- Postconditions:
pm == 0
owns == false
- Throws:
- Nothing.
template <class Mutex>
void swap(unique_lock<Mutex>& x, unique_lock<Mutex>& y);
template <class Mutex>
void swap(unique_lock<Mutex>&& x, unique_lock<Mutex>& y);
template <class Mutex>
void swap(unique_lock<Mutex>& x, unique_lock<Mutex>&& y);
- Effects:
x.swap(y)
.- Throws:
- Nothing.
template <class L1, class L2, class ...L3> int try_lock(L1&, L2&, L3&...);
Each template parameter type shall meet the Mutex requirements,
except that try_lock
is allowed to throw an
exception.
[Note:
The unique_lock
class template meets these requirements
when suitable instantiated.
—end note]
- Effects:
- Calls
try_lock()
for each argument in order beginning with the first until all arguments have been processed, or a call totry_lock()
fails, either by returningfalse
or by throwing an exception. If a call totry_lock()
fails, theunlock()
function is called for any prior arguments.
- Returns:
- If all calls to
try_lock()
returnedtrue
, returns-1
. Otherwise returns a 0-based index value that indicates the argument for whichtry_lock()
returnedfalse
. [Note: On return, either all arguments will be locked or none will be locked. —end note]
template <class L1, class L2, class ...L3> void lock(L1&, L2&, L3&...);
Each template parameter type shall meet the Mutex requirements,
except that try_lock
is allowed to
throw an exception
[Note:
The unique_lock
class template meets these requirements
when suitable instantiated.
—end note]
- Effects:
- All arguments are locked via a sequence of calls to
lock()
,try_lock()
, orunlock()
on the argument. The sequence of calls shall not result in deadlock, but is otherwise unspecified. [Note: A deadlock avoidance algorithm such as try-and-back-off must be used, but the specific algorithm is not specified to avoid over-constraining implementations. —end note] If an exception is thrown by a call tolock()
ortry_lock()
, thenunlock()
will be called for any argument that had been locked by a call tolock()
ortry_lock()
.
Objects of class once_flag
are opaque data structures
that allow call_once
to initialize data
without causing a data race or deadlock.
struct once_flag
[thread.mutex.onceflag]
constexpr once_flag();
- Effects:
- Constructs a object of type
once_flag
.- Synchronization:
- The construction of a once_flag is not synchronized.
- Postconditions:
- Internal state is set to indicate to an invocation of
call_once
with thisonce_flag
as its initial argument that no function has been called.
non-member function call_once
[thread.threads.callonce]
template<class Callable, class Args...>
void call_once(once_flag& flag, Callable func, Args&&... args);
- Requires:
Callable
and eachTi
inArgs
shall beCopyConstructible
if an lvalue and otherwiseMoveConstructible
.INVOKE(func, w1, w2, ..., wN)
([func.require]) shall be a valid expression for some valuesw1, w2, ..., wN
, whereN == sizeof...(Args)
.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:
- Calls to
call_once
on the sameonce_flag
object are serialized. If there has been a prior effectivecall_once
on the same once_flag object, thecall_once
returns without invokingfunc
. If there has been no prior effectivecall_once
on the sameonce_flag
object, the argumentfunc
(or a copy thereof) is called as-if by invokingfunc(args)
. Thecall_once
is effective if and only iffunc(args)
returns without exception. If an exception is thrown, the exception is propagated to the caller.- Synchronization:
- The completion of an effective
call_once
invocation on aonce_flag
object, synchronizes with ([intro.multithread]) all subsequentcall_once
invocations on the sameonce_flag
object.- Throws:
system_error
when the effects cannot be achieved, or any exception propagated fromfunc
.[Example:
// global flag, regular function void init(); std::once_flag flag; void f() { std::call_once(flag,init); } // function static flag, function object struct initializer { void operator()(); }; void g() { static std::once_flag flag2; std::call_once(flag2,initializer); } // object flag, member function class information { std::once_flag verified; void verifier(); public: void verify() { std::call_once(verified,verifier); } };
—end example]
Condition variables provide synchronization primitives
used to block a thread until notified by some other thread
that some condition is met
or until a system time is reached.
Class condition_variable
provides a condition variable
that can only wait on a unique_lock<mutex>
,
allowing maximum efficiency on some platforms.
Class condition_variable_any
provides a general condition variable
that can wait on user supplied lock types.
Condition variables permit concurrent invocation
of the wait
, timed_wait
,
notify_one
and notify_all
member functions.
The execution of notify_one
and notify_all
shall be atomic.
The execution of wait
and timed_wait
shall be performed in three atomic parts:
The implementation shall behave as though
notify_one
, notify_all
,
and each part of
the wait
and timed_wait
executions
are executed in some unspecified total order.
Condition variable construction and destruction need not be synchronized.
<condition_variable> synopsis
namespace std { class condition_variable; class condition_variable_any; } // std
namespace std { class condition_variable { public: condition_variable(); ~condition_variable(); condition_variable(const condition_variable&) = delete; condition_variable& operator=(const condition_variable&) = delete; void notify_one(); void notify_all(); void wait(unique_lock<mutex>& lock); template <class Predicate> void wait(unique_lock<mutex>& lock, Predicate pred); template <class Duration> bool timed_wait(unique_lock<mutex>& lock, const Duration& rel_time); bool timed_wait(unique_lock<mutex>& lock, const system_time& abs_time); template <class Predicate> bool timed_wait(unique_lock<mutex>& lock, const system_time& abs_time, Predicate pred); template <class Duration, class Predicate> bool timed_wait(unique_lock<mutex>& lock, const Duration& rel_time, Predicate pred); typedef implemenation-defined native_handle_type; // See [thread.native] native_handle_type native_handle(); // See [thread.native] }; } // std
condition_variable
shall be a standard-layout class (chapter 9 [class]).
condition_variable();
- Effects:
- Constructs an object of class
condition_variable
.
~condition_variable();
- Precondition:
- There shall be no thread blocked on
*this
. [Note: That is, all threads shall have been notified; they may subsequently block on the lock specified in the wait. Beware that destructing acondition_variable
while the corresponding predicate is false is likely to lead to undefined behavior. —end note]- Effects:
- Destroys the object.
- Throws:
- Nothing.
void notify_one();
- Effects:
- If any threads are blocked waiting for
*this
,notify_one
unblocks one of those threads.
void notify_all();
- Effects:
- Unblock all threads that are blocked waiting for
*this
.
void wait(unique_lock<mutex>& lock);
- Precondition:
lock
is locked by the current thread, and either:
- No other thread is waiting on this
condition_variable
object, or- The
lock
arguments supplied by all concurrently waiting threads (viawait
ortimed_wait
) return the same value forlock.mutex()
.- Effects:
- Atomically calls
lock.unlock()
and blocks on*this
.- When unblocked, calls
lock.lock()
(possibly blocking on the lock) and returns.- The function will unblock when this thread is signaled by a call to
this->notify_one()
, a call tothis->notify_all()
, or spuriously.- If the function exits via an exception,
lock.lock()
will still be called prior to exiting the function scope.- Postconditions:
lock
is locked by the current thread.- Throws:
system_error
when the effects or postconditions cannot be achieved.
template <class Predicate>
void wait(unique_lock<mutex>& lock, Predicate pred);
- Effects:
As if:
while (!pred()) wait(lock);
bool timed_wait(unique_lock<mutex>& lock, const system_time& abs_time);
- Precondition:
lock
is locked by the current thread, and either:
- No other thread is waiting on this
condition_variable
object, or- The
lock
arguments supplied by all concurrently waiting threads (viawait
ortimed_wait
) return the same value forlock.mutex()
.- Effects:
- Atomically calls
lock.unlock()
and blocks on*this
.- When unblocked, calls
lock.lock()
(possibly blocking on the lock) and returns.- The function will unblock when this thread is signaled by a call to
this->notify_one()
, a call tothis->notify_all()
, by the current time exceedingabs_time
, or spuriously.- If the function exits via an exception,
lock.lock()
will still be called prior to exiting the function scope.- Postconditions:
lock
is locked by the current thread.- Returns:
false
if the call is returning because the time specified byabs_time
was reached,true
otherwise.- Throws:
system_error
when the returned value, effects or postconditions cannot be achieved.
template <class Duration>
bool timed_wait(unique_lock<mutex>& lock, const Duration& rel_time);
- Effects:
As if:
timed_wait(lock, get_current_time() + rel_time)
- Returns:
false
if the call is returning because the time duration specified byrel_time
has elapsed,true
otherwise.
template <class Predicate>
bool timed_wait(unique_lock<mutex>& lock, const system_time& abs_time,
Predicate pred);
- Effects:
As if:
while (!pred()) if (!timed_wait(lock, abs_time)) return pred(); return true;
- Returns:
pred()
.[Note: The return value indicates whether the predicate evaluates to
true
, regardless of whether the timeout was triggered. —end note]
template <class Duration, class Predicate>
bool timed_wait(unique_lock<mutex>& lock, const Duration& rel_time,
Predicate pred);
- Effects:
As if:
timed_wait(lock, get_system_time() + rel_time, std::move(pred))
[Note: There is no blocking if
pred()
is initiallytrue
, even if the timeout has already expired. —end note]- Returns:
pred()
.[Note: The return value indicates whether the predicate evaluates to
true
, regardless of whether the timeout was triggered. —end note]
To meet the Lock requirement, types shall meet the Mutex requirement except that
try_lock
is not required.
[Note:
All of the standard mutex types meet this requirement.
—end note]
namespace std { class condition_variable_any { public: condition_variable_any(); ~condition_variable_any(); condition_variable_any(const condition_variable_any&) = delete; condition_variable_any& operator=(const condition_variable_any&) = delete; void notify_one(); void notify_all(); template <class Lock> void wait(Lock& lock); template <class Lock, class Predicate> void wait(Lock& lock, Predicate pred); template <class Lock> bool timed_wait(Lock& lock, const system_time& abs_time); template <class Lock, class Duration> bool timed_wait(Lock& lock, const Duration& rel_time); template <class Lock, class Predicate> bool timed_wait(Lock& lock, const system_time& abs_time, Predicate pred); template <class Lock, class Duration, class Predicate> bool timed_wait(Lock& lock, const Duration& rel_time, Predicate pred); typedef implemenation-defined native_handle_type; // See [thread.native] native_handle_type native_handle(); // See [thread.native] }; } // std
condition_variable_any();
- Effects:
- Constructs an object of class
condition_variable_any
.
~condition_variable_any();
- Precondition:
- There shall be no thread blocked on
*this
. [Note: That is, all threads shall of been notified; they may subsequently block on the lock specified in the wait. Beware that destructing acondition_variable
while the corresponding predicate is false is likely to lead to undefined behavior. —end note]- Effects:
- Destroys the object.
- Throws:
- Nothing.
void notify_one();
- Effects:
- If any threads are blocked waiting for
*this
, unblocks one those threads.
void notify_all();
- Effects:
- Unblock all threads that are blocked waiting for
*this
.
template <class Lock>
void wait(Lock& lock);
- Effects:
- Atomically calls
lock.unlock()
and blocks on*this
.- When unblocked, calls
lock.lock()
(possibly blocking on the lock) and returns.- The function will unblock when this thread is signaled by a call to
this->notify_one()
, a call tothis->notify_all()
, or spuriously.- If the function exits via an exception,
lock.lock()
will still be called prior to exiting the function scope.- Postconditions:
lock
is locked by the current thread.- Throws:
system_error
when the effects or postconditions cannot be achieved.
template <class Lock, class Predicate>
void wait(Lock& lock, Predicate pred);
- Effects:
As if:
while (!pred()) wait(lock);
template <class Lock>
bool timed_wait(Lock& lock, const system_time& abs_time);
- Effects:
- Atomically calls
lock.unlock()
and blocks on*this
.- When unblocked, calls
lock.lock()
(possibly blocking on the lock) and returns.- The function will unblock when this thread is signaled by a call to
this->notify_one()
, a call tothis->notify_all()
, by the current time exceedingabs_time
, or spuriously.- If the function exits via an exception,
lock.lock()
will still be called prior to exiting the function scope.- Postconditions:
lock
is locked by the current thread.- Returns:
false
if the call is returning because the time specified byabs_time
was reached,true
otherwise.- Throws:
system_error
when the returned value, effects or postconditions cannot be achieved.
template <class Lock, class Duration>
bool timed_wait(Lock& lock, const Duration& rel_time);
- Effects:
As if:
timed_wait(lock, get_current_time() + rel_time)
- Returns:
false
if the call is returning because the time duration specified byrel_time
has elapsed,true
otherwise.
template <class Lock, class Predicate>
bool timed_wait(Lock& lock, const system_time& abs_time, Predicate pred);
- Effects:
As if:
while (!pred()) if (!timed_wait(lock, abs_time)) return pred(); return true;
- Returns:
pred()
.[Note: The return value indicates whether the predicate evaluates to
true
, regardless of whether the timeout was triggered. —end note]
template <class Lock, class Duration, class Predicate>
bool timed_wait(Lock& lock, const Duration& rel_time, Predicate pred);
- Effects:
As if:
timed_wait(lock, get_system_time() + rel_time, std::move(pred))
[Note: There is no blocking if
pred()
is initiallytrue
, even if the timeout has already expired. —end note]- Returns:
pred()
.[Note: The return value indicates whether the predicate evaluates to
true
, regardless of whether the timeout was triggered. —end note]
This clause
describes components for determining and manipulating temporal values.
A time point represents a dimensionless instant
in the time continuum.
A time duration represents a length of time
unattached to any time point.
Time points and time durations have a
resolution which is their smallest representable time duration.
Time points
have an epoch or start of a given time scale.
[Example:
For std::time_t
the epoch is
1970-01-01 00:00:00.
—end example]
Throughout this clause,
the names of template parameters are used to express type requirements.
Parameter names
Duration
, LhsDuration
and RhsDuration
express the Duration requirements ([time.duration.requirements]).
For all non-member functions in this clause
that are templated on Duration types,
the implementation shall constrain these function templates such that they will
only instantiate for Duration types.
The Duration
types shall represent durations
of at least ± 292 years.
The system_time
type shall represent times
at least within the range epoch + 292 years.
Header <date_time> Synopsis
namespace std { // duration types class nanoseconds; class microseconds; class milliseconds; class seconds; class minutes; class hours; // timepoint type class system_time; // non-member functions ([time.nonmembers]) system_time get_system_time(); template<typename Duration> system_time operator+(const Duration& td, const system_time& rhs); template <class LhsDuration, class RhsDuration> bool operator==(const LhsDuration& lhs, const RhsDuration& rhs); template <class LhsDuration, class RhsDuration> bool operator!=(const LhsDuration& lhs, const RhsDuration& rhs); template <class LhsDuration, class RhsDuration> bool operator< (const LhsDuration& lhs, const RhsDuration& rhs); template <class LhsDuration, class RhsDuration> bool operator<=(const LhsDuration& lhs, const RhsDuration& rhs); template <class LhsDuration, class RhsDuration> bool operator> (const LhsDuration& lhs, const RhsDuration& rhs); template <class LhsDuration, class RhsDuration> bool operator>=(const LhsDuration& lhs, const RhsDuration& rhs); template <class LhsDuration, class RhsDuration> FinestDuration operator+(const LhsDuration& lhs, const RhsDuration& rhs) template <class LhsDuration, class RhsDuration> FinestDuration operator-(const LhsDuration& lhs, const RhsDuration& rhs) template <class Duration> Duration operator*(Duration lhs, long rhs) template <class Duration> Duration operator*(long lhs, Duration rhs) template <class Duration> Duration operator/(Duration lhs, long rhs) } // std
Through this clause, type FinestDuration
is whichever of LhsDuration
or RhsDuration
has the finest resolution.
If their resolutions are the same,
FinestDuration
is LhsDuration
.
Unless otherwise specified, no function in this clause shall throw exceptions. [Note: Such blanket prohibition of exceptions is unusual in the standard library, but without the prohibition time-related code becomes littered with excessive try-catch blocks. These functions are also unusual in that they encompass virtually no cases where errors can be detected and reported. —end note]
This subclause describes requirements on duration types used to instantiate templates defined in the C++ Standard Library.
Objects of duration types provide time length values which can be positive or negative. Duration types provide comparison and arithmetic operations on those values.
Template definitions in the C++ Standard Library refer to the named Duration requirements for duration types whose details are specified below.
A duration type E
is said to be exactly convertible
to another duration type D
if and only if:
E::is_subsecond
is false
and
D::is_subsecond
is true
, or
E::is_subsecond
is false
and
D::is_subsecond
is false
and
E::seconds_per_tick % D::seconds_per_tick == 0
, or
E::is_subsecond
is true
and
D::is_subsecond
is true
and
D::ticks_per_second % E::ticks_per_second == 0
.
A duration type shall be EqualityComparable, LessThanComparable,
CopyConstructible, DefaultConstructible, CopyAssignable, Swappable, and
Destructible.
In addition, it must meet the requirements
for well-formed expressions specified in the following table,
where D
and E
are duration types,
d
denotes a value of type D
,
d0
denotes d.tick_count()
at entry into the function,
e
denotes a const
value of type E
,
c
denotes a long
value.
E
shall be exactly convertible to D
(diagnostic required).
expression | return type | return value |
---|---|---|
D::tick_type |
implementation defined | |
D::ticks_per_second |
D::tick_type |
The number of ticks per second, or 0 for types for which the number of ticks per second is less than 1. |
D::seconds_per_tick |
D::tick_type |
The number of seconds per tick, or 0 for types for which the number of seconds per tick is less than 1. |
D::is_subsecond |
bool |
seconds_per_tick == 0 |
d.count() |
D::tick_type |
The most recent value established by a non-const function's postcondition. |
-d |
D |
D(-d.tick_count()) |
postcondition | ||
d -= e |
D& |
d.tick_count() ==
d0 - x ,
where x is e.tick_count()
converted to the resolution of D . |
d += e |
D& |
d.tick_count() == d0 + x ,
where x is e.tick_count()
converted to the resolution of D . |
d /= c |
D& |
d.tick_count() == d0 / c |
d *= c |
D& |
d.tick_count()
== d0 * c |
Objects of class nanoseconds
can be used to represent a count of nanoseconds.
Class nanoseconds
shall be a duration type ([time.duration.requirements]).
For the sake of exposition,
the semantics of member functions are not described
if they have the same apparent semantics as specified for duration types.
class nanoseconds { public: // traits information typedef implementation-defined tick_type; static const tick_type ticks_per_second = 1000L * 1000 * 1000; static const tick_type seconds_per_tick = 0; static const bool is_subsecond = true; // construct/copy/destroy functions nanoseconds(long long ns=0); // observer functions tick_type count() const; // modifier functions template<typename RhsDuration> nanoseconds& operator-=(const RhsDuration& d); template<typename RhsDuration> nanoseconds& operator+=(const RhsDuration& d); nanoseconds& operator*=(long multiplier); nanoseconds& operator/=(long divisor); // operations nanoseconds operator-() const; };
nanoseconds(long long ns=0);
- Effects:
- Constructs an object of type
nanoseconds
.- Postcondition:
count() == ns;
Objects of class microseconds
can be used to represent a count of microseconds.
Class microseconds
shall be a duration type ([time.duration.requirements]).
For the sake of exposition, the semantics of member functions are not described
if they have the same apparent semantics as specified for duration types.
class microseconds { public: // traits information typedef implementation-defined tick_type; static const tick_type ticks_per_second = 1000L * 1000; static const tick_type seconds_per_tick = 0; static const bool is_subsecond = true; // construct/copy/destroy functions microseconds(long long us=0); // observer functions tick_type count() const; // modifier functions template<typename RhsDuration> microseconds& operator-=(const RhsDuration& d); template<typename RhsDuration> microseconds& operator+=(const RhsDuration& d); microseconds& operator*=(long multiplier); microseconds& operator/=(long divisor); // operations microseconds operator-() const; // conversions operator nanoseconds() const; };
microseconds(long long us=0);
- Effects:
- Constructs an object of type
microseconds
.- Postcondition:
count() == us;
operator nanoseconds() const;
- Returns:
count() * (nanoseconds::ticks_per_second / microseconds::ticks_per_second)
.
Objects of class milliseconds
can be used to represent a count of milliseconds.
Class milliseconds
shall be a duration type ([time.duration.requirements]).
For the sake of exposition,
the semantics of member functions are not described
if they have the same apparent semantics as specified for duration types.
class milliseconds { public: // traits information typedef implementation-defined tick_type; static const tick_type ticks_per_second = 1000; static const tick_type seconds_per_tick = 0; static const bool is_subsecond = true; // construct/copy/destroy functions milliseconds(long long ms=0); // observer functions tick_type count() const; // modifier functions template<typename RhsDuration> milliseconds& operator-=(const RhsDuration& d); template<typename RhsDuration> milliseconds& operator+=(const RhsDuration& d); milliseconds& operator*=(long multiplier); milliseconds& operator/=(long divisor); // operations milliseconds operator-() const; // conversions operator nanoseconds() const; operator microseconds() const; };
milliseconds(long long ms=0);
- Effects:
- Constructs an object of type
milliseconds
.- Postcondition:
count() == ms;
operator nanoseconds() const;
- Returns:
count() * (nanoseconds::ticks_per_second / milliseconds::ticks_per_second)
.
operator microseconds() const;
- Returns:
count() * (microseconds::ticks_per_second / milliseconds::ticks_per_second)
.
Objects of class seconds
can be used to represent a count of seconds.
Class seconds
shall be a duration type ([time.duration.requirements]).
For the sake of exposition,
the semantics of member functions are not described
if they have the same apparent semantics as specified for duration types.
class seconds { public: // traits information typedef implementation-defined tick_type; static const tick_type ticks_per_second = 1; static const tick_type seconds_per_tick = 1; static const bool is_subsecond = false; // construct/copy/destroy functions seconds(long long s=0); // observer functions tick_type count() const; // modifier functions template<typename RhsDuration> seconds& operator-=(const RhsDuration& d); template<typename RhsDuration> seconds& operator+=(const RhsDuration& d); seconds& operator*=(long multiplier); seconds& operator/=(long divisor); // operations seconds operator-() const; // conversions operator nanoseconds() const; operator microseconds() const; operator milliseconds() const; };
seconds(long long s=0);
- Effects:
- Constructs an object of type
seconds
.- Postcondition:
count() == s;
operator nanoseconds() const;
- Returns:
count() * (seconds::seconds_per_tick * nanoseconds::ticks_per_second)
.
operator microseconds() const;
- Returns:
count() * (seconds::seconds_per_tick * microseconds::ticks_per_second)
.
operator milliseconds() const;
- Returns:
count() * (seconds::seconds_per_tick * milliseconds::ticks_per_second)
.
Objects of class minutes
can be used to represent a count of minutes.
Class minutes
shall be a duration type ([time.duration.requirements]).
For the sake of exposition,
the semantics of member functions are not described
if they have the same apparent semantics as specified for duration types.
class minutes { public: // traits information typedef implementation-defined tick_type; static const tick_type ticks_per_second = 0; static const tick_type seconds_per_tick = 60; static const bool is_subsecond = false; // construct/copy/destroy functions minutes(long long m=0); // observer functions tick_type count() const; // modifier functions template<typename RhsDuration> minutes& operator-=(const RhsDuration& d); template<typename RhsDuration> minutes& operator+=(const RhsDuration& d); minutes& operator*=(long multiplier); minutes& operator/=(long divisor); // operations minutes operator-() const; // conversions operator nanoseconds() const; operator microseconds() const; operator milliseconds() const; operator seconds() const; };
minutes(long long m=0);
- Effects:
- Constructs an object of type
minutes
.- Postcondition:
count() == m;
operator nanoseconds() const;
- Returns:
count() * (minutes::seconds_per_tick * nanoseconds::ticks_per_second)
.
operator microseconds() const;
- Returns:
count() * (minutes::seconds_per_tick * microseconds::ticks_per_second)
.
operator milliseconds() const;
- Returns:
count() * (minutes::seconds_per_tick * milliseconds::ticks_per_second)
.
operator seconds() const;
- Returns:
count() * (minutes::seconds_per_tick / seconds::seconds_per_tick)
.
Objects of class hours
can be used to represent a count of hours.
Class hours
shall be a duration type ([time.duration.requirements]).
For the sake of exposition,
the semantics of member functions are not described
if they have the same apparent semantics as specified for duration types.
class hours { public: // traits information typedef implementation-defined tick_type; static const tick_type ticks_per_second = 0; static const tick_type seconds_per_tick = 3600; static const bool is_subsecond = false; // construct/copy/destroy functions hours(long long h=0); // observer functions tick_type count() const; // modifier functions template<typename RhsDuration> hours& operator-=(const RhsDuration& d); template<typename RhsDuration> hours& operator+=(const RhsDuration& d); hours& operator*=(long multiplier); hours& operator/=(long divisor); // operations hours operator-() const; // conversions operator nanoseconds() const; operator microseconds() const; operator milliseconds() const; operator seconds() const; operator minutes() const; };
hours(long long h=0);
- Effects:
- Constructs an object of type
hours
.- Postcondition:
count() == h;
operator nanoseconds() const;
- Returns:
count() * (hours::seconds_per_tick * nanoseconds::ticks_per_second)
.
operator microseconds() const;
- Returns:
count() * (hours::seconds_per_tick * microseconds::ticks_per_second)
.
operator milliseconds() const;
- Returns:
count() * (hours::seconds_per_tick * milliseconds::ticks_per_second)
.
operator seconds() const;
- Returns:
count() * (hours::seconds_per_tick / seconds::seconds_per_tick)
.
operator minutes() const;
- Returns:
count() * (hours::seconds_per_tick / minutes::seconds_per_tick)
.
The class system_time
provides a time point
that represents the current
Coordinated Universal Time, known as UTC, time.
system_time
shall provide an epoch time of 1970-01-01 00:00:00.000000000
and a maximum time value of at least epoch time + 292 years.
[Note:
292 years represents the number of nanoseconds
that can be represented in a signed 64 bit integer.
—end note]
class system_time { public: system_time(); explicit system_time(time_t, nanoseconds ns=0); time_t seconds_since_epoch() const; nanoseconds nanoseconds_since_epoch() const; // traits typedef implementation defined tick_type; static const tick_type ticks_per_second = nanoseconds::ticks_per_second; static const tick_type seconds_per_tick = 0; static const bool is_subsecond = true; // comparison functions bool operator==(const system_time& rhs) const; bool operator!=(const system_time& rhs) const; bool operator>(const system_time& rhs) const; bool operator>=(const system_time& rhs) const; bool operator<(const system_time& rhs) const; bool operator<=(const system_time& rhs) const; // arithmetic functions nanoseconds operator-(const system_time& rhs) const template<typename Duration> system_time operator+(const Duration& td) const; template<typename Duration> system_time& operator+=(const Duration& td); template<typename Duration> system_time operator-(const Duration& td) const; template<typename Duration> system_time& operator-=(const Duration& td) };
system_time();
- Effects:
- Constructs a
system_time
object representing the epoch time.
system_time(time_t secs, nanoseconds ns=0);
- Effects:
- Constructs a
system_time
time object representing the time pointsecs + ns / 1,000,000,000
seconds after the epoch.- Remarks:
- If the total nanoseconds is greater than 1 second, the seconds are incremented appropriately.
time_t seconds_since_epoch() const;
- Returns:
- The seconds since the epoch time represented by the current value of
*this
.
nanoseconds nanoseconds_since_epoch() const;
- Returns:
- The nanoseconds since the epoch time represented by the current value of
*this
.
bool operator==(const system_time& rhs) const;
- Returns:
- True if the time point represented by
*this
is the same as the time point represented byrhs
.
bool operator!=(const system_time& rhs) const;
- Returns:
- True if the time point represented by
*this
is not the same as the time point represented byrhs
.
bool operator>(const system_time& rhs) const;
- Returns:
- True if the time point represented by
*this
is later than the time point represented byrhs
.
bool operator>=(const system_time& rhs) const;
- Returns:
- True if the time point represented by
*this
is later or the same as the time point represented byrhs
.
bool operator<(const system_time& rhs) const;
- Returns:
- True if the time point represented by
*this
is earlier than the time point represented byrhs
.
bool operator<=(const system_time& rhs) const;
- Returns:
- True if the time point represented by
*this
is earlier or the same as the time point represented byrhs
.
nanoseconds operator-(const system_time& rhs) const
- Returns:
- The difference in nanoseconds between the time point represented by
*this
and the time point represented byrhs
.- Remarks:
- If
*this < rhs
, the result will be negative.
template<typename Duration>
system_time operator+(const Duration& td) const;
- Returns:
system_time(*this) += td
.
template<typename Duration>
system_time& operator+=(const Duration& td);
- Effects:
- Converts
td
to nanosecond resolution and adds it to the time represented by*this
.- Returns:
*this
template<typename Duration>
system_time operator-(const Duration& td) const;
- Returns:
system_time(*this) -= td
.
template<typename Duration>
system_time& operator-=(const Duration& td)
- Effects:
- Converts
td
to nanosecond resolution and subtracts it from the time represented by*this
.- Returns:
*this
system_time get_system_time();
- Returns:
- The system time as provided by the operating system. [Note: Provides access to the system clock at a resolution as fine as nanoseconds. The actual resolution may vary. —end note] [Note: No error reporting is provided. Hosted implementations ([intro.compliance]) presumably utilize system clock API's that never report errors. —end note]
template<typename Duration>
system_time operator+(const Duration& td, const system_time& rhs);
- Returns:
rhs + td
.
template <class LhsDuration, class RhsDuration>
bool operator==(const LhsDuration& lhs, const RhsDuration& rhs);
- Requires:
- Either
LhsDuration
shall be exactly convertible toRhsDuration
orRhsDuration
shall be exactly convertible toLhsDuration
(diagnostic required).- Returns:
FinestDuration(lhs.count()) == FinestDuration(rhs.count())
See [time] for description of
FinestDuration
.
template <class LhsDuration, class RhsDuration>
bool operator!=(const LhsDuration& lhs, const RhsDuration& rhs);
- Requires:
- Either
LhsDuration
shall be exactly convertible toRhsDuration
orRhsDuration
shall be exactly convertible toLhsDuration
(diagnostic required).- Returns:
!(lhs==rhs)
.
template <class LhsDuration, class RhsDuration>
bool operator< (const LhsDuration& lhs, const RhsDuration& rhs);
- Requires:
- Either
LhsDuration
shall be exactly convertible toRhsDuration
orRhsDuration
shall be exactly convertible toLhsDuration
(diagnostic required).- Returns:
FinestDuration(lhs.count()) < FinestDuration(rhs.count())
See [time] for description of
FinestDuration
.
template <class LhsDuration, class RhsDuration>
bool operator<=(const LhsDuration& lhs, const RhsDuration& rhs);
- Requires:
- Either
LhsDuration
shall be exactly convertible toRhsDuration
orRhsDuration
shall be exactly convertible toLhsDuration
(diagnostic required).- Returns:
!(rhs<lhs)
.
template <class LhsDuration, class RhsDuration>
bool operator> (const LhsDuration& lhs, const RhsDuration& rhs);
- Requires:
- Either
LhsDuration
shall be exactly convertible toRhsDuration
orRhsDuration
shall be exactly convertible toLhsDuration
(diagnostic required).- Returns:
rhs<lhs
.
template <class LhsDuration, class RhsDuration>
bool operator>=(const LhsDuration& lhs, const RhsDuration& rhs);
- Requires:
- Either
LhsDuration
shall be exactly convertible toRhsDuration
orRhsDuration
shall be exactly convertible toLhsDuration
(diagnostic required).- Returns:
!(lhs<rhs)
.
template <class LhsDuration, class RhsDuration>
FinestDuration operator+(const LhsDuration& lhs, const RhsDuration& rhs)
- Requires:
- Either
LhsDuration
shall be exactly convertible toRhsDuration
orRhsDuration
shall be exactly convertible toLhsDuration
(diagnostic required).- Returns:
FinestDuration(lhs.count())+FinestDuration(rhs.count())
See [time] for description of
FinestDuration
.
template <class LhsDuration, class RhsDuration>
FinestDuration operator-(const LhsDuration& lhs, const RhsDuration& rhs)
- Requires:
- Either
LhsDuration
shall be exactly convertible toRhsDuration
orRhsDuration
shall be exactly convertible toLhsDuration
(diagnostic required).- Returns:
FinestDuration(lhs.count())-FinestDuration(rhs.count())
See [time] for description of
FinestDuration
.
template <class Duration>
Duration operator*(Duration lhs, long rhs)
- Returns:
lhs *= rhs
.
template <class Duration>
Duration operator*(long lhs, Duration rhs)
- Returns:
rhs *= lhs
.
template <class Duration>
Duration operator/(Duration lhs, long rhs)
- Returns:
lhs /= rhs
.
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. Pete Becker also contributed numerous critiques, suggestions, and comments on the current proposal, which are most appreciated. Jeff Garland contributed the date time portions of the proposal based on the Boost.DateTime Library and his TR2 proposals.