A
lock is an object that holds a reference to a lockable object and may unlock the
lockable object during the lock's destruction (such as when leaving block scope)
. An execution
agent may use a lock to aid in managing ownership of a lockable object in an exception safe
manner
. A lock is said to
own a lockable object if it is currently managing the
ownership of that lockable object for an execution agent
. A lock does not manage the lifetime
of the lockable object it references
. [
Note: Locks are intended to ease the burden of
unlocking the lockable object under both normal and exceptional circumstances
. —
end note ]
namespace std {
template <class Mutex>
class lock_guard {
public:
using mutex_type = Mutex;
explicit lock_guard(mutex_type& m);
lock_guard(mutex_type& m, adopt_lock_t);
~lock_guard();
lock_guard(const lock_guard&) = delete;
lock_guard& operator=(const lock_guard&) = delete;
private:
mutex_type& pm; };
template<class Mutex> lock_guard(lock_guard<Mutex>) -> lock_guard<Mutex>;
}
An object of type
lock_guard controls the ownership of a lockable object
within a scope
. A
lock_guard object maintains ownership of a lockable
object throughout the
lock_guard object's lifetime (
[basic.life])
. The behavior of a program is undefined if the lockable object referenced by
pm does not exist for the entire lifetime of the
lock_guard
object
. explicit lock_guard(mutex_type& m);
Requires: If
mutex_type is not a recursive mutex,
the calling thread does not own the mutex
m. Effects: As if by
m.lock(). lock_guard(mutex_type& m, adopt_lock_t);
Requires: The calling thread owns the mutex
m. ~lock_guard();
Effects: As if by
pm.unlock().
namespace std {
template <class... MutexTypes>
class scoped_lock {
public:
using mutex_type = Mutex;
explicit scoped_lock(MutexTypes&... m);
explicit scoped_lock(MutexTypes&... m, adopt_lock_t);
~scoped_lock();
scoped_lock(const scoped_lock&) = delete;
scoped_lock& operator=(const scoped_lock&) = delete;
private:
tuple<MutexTypes&...> pm; };
template<class... MutexTypes>
scoped_lock(scoped_lock<MutexTypes...>) -> scoped_lock<MutexTypes...>;
}
An object of type
scoped_lock controls the ownership of lockable objects
within a scope
. A
scoped_lock object maintains ownership of lockable
objects throughout the
scoped_lock object's lifetime (
[basic.life])
. The behavior of a program is undefined if the lockable objects referenced by
pm do not exist for the entire lifetime of the
scoped_lock
object
. explicit scoped_lock(MutexTypes&... m);
Requires: If a
MutexTypes type is not a recursive mutex,
the calling thread does not own the corresponding mutex element of
m. Effects: Initializes
pm with
tie(m...). Then if
sizeof...(MutexTypes) is
0, no effects
. Otherwise if
sizeof...(MutexTypes) is
1, then
m.lock(). explicit scoped_lock(MutexTypes&... m, adopt_lock_t);
Requires: The calling thread owns all the mutexes in
m. Effects: Initializes
pm with
tie(m...). ~scoped_lock();
Effects: For all
i in
[0, sizeof...(MutexTypes)),
get<i>(pm).unlock().
namespace std {
template <class Mutex>
class unique_lock {
public:
using mutex_type = Mutex;
unique_lock() noexcept;
explicit unique_lock(mutex_type& m);
unique_lock(mutex_type& m, defer_lock_t) noexcept;
unique_lock(mutex_type& m, try_to_lock_t);
unique_lock(mutex_type& m, adopt_lock_t);
template <class Clock, class Duration>
unique_lock(mutex_type& m, const chrono::time_point<Clock, Duration>& abs_time);
template <class Rep, class Period>
unique_lock(mutex_type& m, const chrono::duration<Rep, Period>& rel_time);
~unique_lock();
unique_lock(const unique_lock&) = delete;
unique_lock& operator=(const unique_lock&) = delete;
unique_lock(unique_lock&& u) noexcept;
unique_lock& operator=(unique_lock&& u);
void lock();
bool try_lock();
template <class Rep, class Period>
bool try_lock_for(const chrono::duration<Rep, Period>& rel_time);
template <class Clock, class Duration>
bool try_lock_until(const chrono::time_point<Clock, Duration>& abs_time);
void unlock();
void swap(unique_lock& u) noexcept;
mutex_type* release() noexcept;
bool owns_lock() const noexcept;
explicit operator bool () const noexcept;
mutex_type* mutex() const noexcept;
private:
mutex_type* pm; bool owns; };
template<class Mutex> unique_lock(unique_lock<Mutex>) -> unique_lock<Mutex>;
template <class Mutex>
void swap(unique_lock<Mutex>& x, unique_lock<Mutex>& y) noexcept;
}
An object of type
unique_lock controls the ownership of a lockable
object within a scope
. Ownership of the lockable object may be acquired at
construction or after construction, and may be transferred, after
acquisition, to another
unique_lock object
. Objects of type
unique_lock are not
copyable but are movable
. The behavior of a program is undefined if the contained pointer
pm is not null and the lockable object pointed
to by
pm does not exist for the entire remaining
lifetime (
[basic.life]) of the
unique_lock object
. [
Note: unique_lock<Mutex> meets the
BasicLockable requirements
. If
Mutex
meets the
Lockable requirements (
[thread.req.lockable.req]),
unique_lock<Mutex> also meets the
Lockable requirements;
if
Mutex
meets the
TimedLockable requirements (
[thread.req.lockable.timed]),
unique_lock<Mutex> also meets the
TimedLockable requirements
. —
end note ]
unique_lock() noexcept;
Effects: Constructs an object of type
unique_lock. Postconditions: pm == 0 and
owns == false. explicit unique_lock(mutex_type& m);
Requires: If
mutex_type is not a recursive mutex the calling thread does not own the mutex
. Effects: Constructs an object of type
unique_lock and calls
m.lock(). Postconditions: pm == addressof(m) and
owns == true. unique_lock(mutex_type& m, defer_lock_t) noexcept;
Effects: Constructs an object of type
unique_lock. Postconditions: pm == addressof(m) and
owns == false. unique_lock(mutex_type& m, try_to_lock_t);
If
mutex_type is not a recursive mutex the calling thread does not own the mutex
. Effects: Constructs an object of type
unique_lock and calls
m.try_lock(). Postconditions: pm == addressof(m) and
owns == res,
where
res is the value returned by the call to
m.try_lock(). unique_lock(mutex_type& m, adopt_lock_t);
Requires: The calling thread owns the mutex
. Effects: Constructs an object of type
unique_lock. Postconditions: pm == addressof(m) and
owns == true. template <class Clock, class Duration>
unique_lock(mutex_type& m, const chrono::time_point<Clock, Duration>& abs_time);
Requires: If
mutex_type is not a recursive mutex the calling thread
does not own the mutex
. Effects: Constructs an object of type
unique_lock and calls
m.try_lock_until(abs_time). Postconditions: pm == addressof(m) and
owns == res,
where
res is
the value returned by the call to
m.try_lock_until(abs_time). template <class Rep, class Period>
unique_lock(mutex_type& m, const chrono::duration<Rep, Period>& rel_time);
Requires: If
mutex_type is not a recursive mutex the calling thread does not own the mutex
. Effects: Constructs an object of type
unique_lock and calls
m.try_lock_for(rel_time). Postconditions: pm == addressof(m) and
owns == res,
where
res is the value returned by the call to
m.try_lock_for(rel_time). unique_lock(unique_lock&& u) noexcept;
Postconditions: pm == u_p.pm and
owns == u_p.owns (where
u_p is the state of
u just prior to this construction),
u.pm == 0 and
u.owns == false. unique_lock& operator=(unique_lock&& u);
Effects: If
owns calls
pm->unlock(). Postconditions: pm == u_p.pm and
owns == u_p.owns (where
u_p is the state of
u just prior to this construction),
u.pm == 0 and
u.owns == false. [
Note: With a recursive mutex it is possible for both
*this and
u to own the same mutex before the assignment
. In this case,
*this will own the mutex after the assignment and
u will not
. —
end note ]
~unique_lock();
Effects: If
owns calls
pm->unlock(). void lock();
Effects: As if by
pm->lock(). Postconditions: owns == true. Throws:
Any exception thrown by
pm->lock(). Error conditions:
operation_not_permitted — if
pm is
nullptr. resource_deadlock_would_occur — if on entry
owns
is
true.
bool try_lock();
Effects: As if by
pm->try_lock(). Returns: The value returned by the call to
try_lock(). Postconditions: owns == res, where
res is the value returned by
the call to
try_lock(). Throws:
Any exception thrown by
pm->try_lock(). Error conditions:
operation_not_permitted — if
pm is
nullptr. resource_deadlock_would_occur — if on entry
owns
is
true.
template <class Clock, class Duration>
bool try_lock_until(const chrono::time_point<Clock, Duration>& abs_time);
Effects: As if by
pm->try_lock_until(abs_time). Returns: The value returned by the call to
try_lock_until(abs_time). Postconditions: owns == res, where
res is the value returned by
the call to
try_lock_until(abs_time). Throws: Any exception thrown by
pm->try_lock_until(). Error conditions:
operation_not_permitted — if
pm is
nullptr. resource_deadlock_would_occur — if on entry
owns is
true.
template <class Rep, class Period>
bool try_lock_for(const chrono::duration<Rep, Period>& rel_time);
Effects: As if by
pm->try_lock_for(rel_time). Returns: The value returned by the call to
try_lock_until(rel_time). Postconditions: owns == res, where
res is the value returned by the call to
try_lock_for(rel_time). Throws: Any exception thrown by
pm->try_lock_for(). Error conditions:
operation_not_permitted — if
pm is
nullptr. resource_deadlock_would_occur — if on entry
owns is
true.
void unlock();
Effects: As if by
pm->unlock(). Postconditions: owns == false. Error conditions:
operation_not_permitted — if on entry
owns is
false.
void swap(unique_lock& u) noexcept;
Effects: Swaps the data members of
*this and
u. mutex_type* release() noexcept;
Returns: The previous value of
pm. Postconditions: pm == 0 and
owns == false. template <class Mutex>
void swap(unique_lock<Mutex>& x, unique_lock<Mutex>& y) noexcept;
Effects: As if by
x.swap(y). bool owns_lock() const noexcept;
explicit operator bool() const noexcept;
mutex_type *mutex() const noexcept;
namespace std {
template <class Mutex>
class shared_lock {
public:
using mutex_type = Mutex;
shared_lock() noexcept;
explicit shared_lock(mutex_type& m); shared_lock(mutex_type& m, defer_lock_t) noexcept;
shared_lock(mutex_type& m, try_to_lock_t);
shared_lock(mutex_type& m, adopt_lock_t);
template <class Clock, class Duration>
shared_lock(mutex_type& m,
const chrono::time_point<Clock, Duration>& abs_time);
template <class Rep, class Period>
shared_lock(mutex_type& m,
const chrono::duration<Rep, Period>& rel_time);
~shared_lock();
shared_lock(const shared_lock&) = delete;
shared_lock& operator=(const shared_lock&) = delete;
shared_lock(shared_lock&& u) noexcept;
shared_lock& operator=(shared_lock&& u) noexcept;
void lock(); bool try_lock();
template <class Rep, class Period>
bool try_lock_for(const chrono::duration<Rep, Period>& rel_time);
template <class Clock, class Duration>
bool try_lock_until(const chrono::time_point<Clock, Duration>& abs_time);
void unlock();
void swap(shared_lock& u) noexcept;
mutex_type* release() noexcept;
bool owns_lock() const noexcept;
explicit operator bool () const noexcept;
mutex_type* mutex() const noexcept;
private:
mutex_type* pm; bool owns; };
template<class Mutex> shared_lock(shared_lock<Mutex>) -> shared_lock<Mutex>;
template <class Mutex>
void swap(shared_lock<Mutex>& x, shared_lock<Mutex>& y) noexcept;
}
An object of type
shared_lock controls the shared ownership of a
lockable object within a scope
. Shared ownership of the lockable object may be
acquired at construction or after construction, and may be transferred, after
acquisition, to another
shared_lock object
. Objects of type
shared_lock are not copyable but are movable
. The behavior of a program
is undefined if the contained pointer
pm is not null and the lockable
object pointed to by
pm does not exist for the entire remaining
lifetime (
[basic.life]) of the
shared_lock object
. shared_lock() noexcept;
Effects: Constructs an object of type
shared_lock. Postconditions: pm == nullptr and
owns == false. explicit shared_lock(mutex_type& m);
Requires: The calling thread does not own the mutex for any ownership mode
. Effects: Constructs an object of type
shared_lock and calls
m.lock_shared(). Postconditions: pm == addressof(m) and
owns == true. shared_lock(mutex_type& m, defer_lock_t) noexcept;
Effects: Constructs an object of type
shared_lock. Postconditions: pm == addressof(m) and
owns == false. shared_lock(mutex_type& m, try_to_lock_t);
Requires: The calling thread does not own the mutex for any ownership mode
. Effects: Constructs an object of type
shared_lock and calls
m.try_lock_shared(). Postconditions: pm == addressof(m) and
owns == res
where
res is the
value returned by the call to
m.try_lock_shared(). shared_lock(mutex_type& m, adopt_lock_t);
Requires: The calling thread has shared ownership of the mutex
. Effects: Constructs an object of type
shared_lock. Postconditions: pm == addressof(m) and
owns == true. template <class Clock, class Duration>
shared_lock(mutex_type& m,
const chrono::time_point<Clock, Duration>& abs_time);
Requires: The calling thread does not own the mutex for any ownership mode
. Effects: Constructs an object of type
shared_lock and calls
m.try_lock_shared_until(abs_time). Postconditions: pm == addressof(m) and
owns == res
where
res
is the value returned by the call to
m.try_lock_shared_until(abs_time). template <class Rep, class Period>
shared_lock(mutex_type& m,
const chrono::duration<Rep, Period>& rel_time);
Requires: The calling thread does not own the mutex for any ownership mode
. Effects: Constructs an object of type
shared_lock and calls
m.try_lock_shared_for(rel_time). Postconditions: pm == addressof(m) and
owns == res
where
res is
the value returned by the call to
m.try_lock_shared_for(rel_time). ~shared_lock();
Effects: If
owns calls
pm->unlock_shared(). shared_lock(shared_lock&& sl) noexcept;
Postconditions: pm == sl_p.pm and
owns == sl_p.owns (where
sl_p is the state of
sl just prior to this construction),
sl.pm == nullptr and
sl.owns == false. shared_lock& operator=(shared_lock&& sl) noexcept;
Effects: If
owns calls
pm->unlock_shared(). Postconditions: pm == sl_p.pm and
owns == sl_p.owns (where
sl_p is the state of
sl just prior to this assignment),
sl.pm == nullptr and
sl.owns == false. void lock();
Effects: As if by
pm->lock_shared(). Postconditions: owns == true. Throws: Any exception thrown by
pm->lock_shared(). Error conditions:
operation_not_permitted — if
pm is
nullptr. resource_deadlock_would_occur — if on entry
owns is
true.
bool try_lock();
Effects: As if by
pm->try_lock_shared(). Returns: The value returned by the call to
pm->try_lock_shared(). Postconditions: owns == res, where
res is the value returned by
the call to
pm->try_lock_shared(). Throws: Any exception thrown by
pm->try_lock_shared(). Error conditions:
operation_not_permitted — if
pm is
nullptr. resource_deadlock_would_occur — if on entry
owns is
true.
template <class Clock, class Duration>
bool
try_lock_until(const chrono::time_point<Clock, Duration>& abs_time);
Effects: As if by
pm->try_lock_shared_until(abs_time). Returns: The value returned by the call to
pm->try_lock_shared_until(abs_time). Postconditions: owns == res, where
res is the value returned by
the call to
pm->try_lock_shared_until(abs_time). Throws: Any exception thrown by
pm->try_lock_shared_until(abs_time). Error conditions:
operation_not_permitted — if
pm is
nullptr. resource_deadlock_would_occur — if on entry
owns is
true.
template <class Rep, class Period>
bool try_lock_for(const chrono::duration<Rep, Period>& rel_time);
Effects: As if by
pm->try_lock_shared_for(rel_time). Returns: The value returned by the call to
pm->try_lock_shared_for(rel_time). Postconditions: owns == res, where
res is the value returned by the call to
pm->try_lock_shared_for(rel_time). Throws: Any exception thrown by
pm->try_lock_shared_for(rel_time). Error conditions:
operation_not_permitted — if
pm is
nullptr. resource_deadlock_would_occur — if on entry
owns is
true.
void unlock();
Effects: As if by
pm->unlock_shared(). Postconditions: owns == false. Error conditions:
operation_not_permitted — if on entry
owns is
false.
void swap(shared_lock& sl) noexcept;
Effects: Swaps the data members of
*this and
sl. mutex_type* release() noexcept;
Returns: The previous value of
pm. Postconditions: pm == nullptr and
owns == false. template <class Mutex>
void swap(shared_lock<Mutex>& x, shared_lock<Mutex>& y) noexcept;
Effects: As if by
x.swap(y). bool owns_lock() const noexcept;
explicit operator bool() const noexcept;
mutex_type* mutex() const noexcept;