<mutex>[added with C++11]
adopt_lock
· adopt_lock_t
· call_once
· defer_lock
· defer_lock_t
· lock
· lock_guard
· mutex
· once_flag
· recursive_mutex
· recursive_timed_mutex
· swap
· timed_mutex
· try_lock
· try_to_lock
· try_to_lock_t
· unique_lock
Include the standard header <mutex> to define
the classes mutex, recursive_mutex,
timed_mutex, and recursive_timed_mutex,
the templates lock_guard and unique_lock,
and various supporting types and functions for defining
mutual exclusion code regions.
The classes mutex and recursive_mutex are
mutex types. Objects of these types have member
functions that lock and unlock them, providing mutual exclusion when multiple
threads try to lock the same mutex object. Mutex types can be used as type
arguments to instantiate the templates lock_guard and
unique_lock. Objects of these types can be used as the
Lock argument to the wait member functions in the
template
condition_variable_any.
The classes timed_mutex and recursive_timed_mutex
are
timed mutex types. These types can be used
anywhere a mutex type can be used. In addition to the member functions in
mutex types, objects of these types have member functions that will try to
lock them but will return after a specified time if they cannot get the lock.
Objects of these types can be used as the Lock arguments to
instantiate the wait_for and the wait_until member
functions in the template
condition_variable_any.
namespace std {
// MUTUAL EXCLUSION
class mutex;
class recursive_mutex;
class timed_mutex;
class recursive_timed_mutex;
// LOCK PROPERTIES
struct adopt_lock_t;
struct defer_lock_t;
struct try_to_lock_t;
constexpr adopt_lock_t adopt_lock { };
constexpr const defer_lock_t defer_lock { };
constexpr const try_to_lock_t try_to_lock { };
// LOCKS
template<class Mutex>
class lock_guard;
template<class Mutex>
class unique_lock;
// SWAP
template<class Mutex>
void swap(unique_lock<Mutex>& Left,
unique_lock<Mutex>& Right) noexcept;
// MULTIPLE LOCKS
template<class L1, class L2, class... L3>
void lock(L1&, L2&, L3&...);
template<class L1, class L2, class... L3>
int try_lock(L1&, L2&, L3&...);
// CALL ONCE
struct once_flag;
template<class Callable, class... Args>
void call_once(once_flag& flag,
Callable&& F, Args&&... A);
} // namespace std
adopt_lockconstexpr adopt_lock_t adopt_lock { };
The object can be passed to constructors for lock_guard and
unique_lock to indicate that the mutex object that is also being
passed to the constructor is locked.
adopt_lock_tstruct adopt_lock_t { };
The type is used to define an object, adopt_lock,
that can be used to select one of the overloaded constructors of lock_guard
and of unique_lock.
call_oncetemplate<class Callable, class... Args>
void call_once(once_flag& Flag,
Callable F&&, Args&&... A);
If Flag is not valid, the function throws an object of type
system_error with an error code of
invalid_argument. Otherwise, the template function uses its
Flag argument to ensure that it calls F(A...)
successfully exactly once, regardless of how many times the template function
is called. If F(A...) exits by throwing an exception it is not a
successful call.
defer_lockconstexpr defer_lock_t defer_lock { };
The object can be passed to the constructor for unique_lock to
indicate that the constructor should not lock the mutex object that is also
being passed to it.
defer_lock_tstruct defer_lock_t { };
The type is used to define an object, defer_lock, that can be
used to select one of the overloaded constructors of
unique_lock.
locktemplate<class L1, class L2, class... L3>
void lock(L1&, L2&, L3&...);
The arguments to the template function must be
mutex types,
except that calls to try_lock may throw exceptions.
The function locks all of its arguments without deadlock by calls to
lock, try_lock, and unlock. If a call
to lock or try_lock throws an exception, the
function calls unlock on any of the mutex objects that were
successfully locked before rethrowing the exception.
lock_guardlock_guard
· ~lock_guard
· mutex_type
template<class Mutex>
class lock_guard
{
public:
typedef Mutex mutex_type;
explicit lock_guard(mutex_type& mtx);
lock_guard(mutex_type& mtx, adopt_lock_t);
~lock_guard();
lock_guard(const lock_guard&) = delete;
lock_guard& operator=(const lock_guard&) = delete;
};
The template can be instantiated to create an object whose destructor
unlocks a mutex. The template argument Mutex must name a
mutex type.
lock_guard::lock_guardexplicitlock_guard(mutex_type& mtx); lock_guard(mutex_type& mtx, adopt_lock_t);
The first constructor constructs an object of type lock_guard
and locks the mutex mtx. If mtx is not a recursive
mutex, it must not be locked when this constructor is called.
The second constructor constructs an object of type lock_guard
but does not lock the mutex mtx. mtx must be locked
when this constructor is called. The constructor throws nothing.
lock_guard::~lock_guard~lock_guard();
The destructor unlocks the mutex that was passed to the constructor. If the mutex does not exist at the time that the destructor runs, the behavior is undefined.
lock_guard::mutex_typetypedef Mutex mutex_type;
The typedef name is a synonym for the template argument
Mutex.
mutexlock
· mutex
· ~mutex
· native_handle
· native_handle_type
· try_lock
· unlock
class mutex
{
public:
constexpr mutex() noexcept;
~mutex();
mutex(const mutex&) = delete;
mutex& operator=(const mutex&) = delete;
void lock();
bool try_lock();
void unlock();
typedef see below native_handle_type;
native_handle_type native_handle();
};
The class mutex is a
mutex_type. Objects of this type can be used to
enforce mutual exclusion within a program.
mutex::lockvoid lock();
The member function blocks the calling thread until the calling thread
obtains ownership of the mutex. If the calling thread already owns the mutex,
the function throws an object of type system_error
with an error code of resource_deadlock_would_occur.
mutex::mutexconstexpr mutex() noexcept;
The constructor constructs a mutex object that is not locked.
mutex::~mutex~mutex();
The destructor releases any resources used by the mutex
object. If the object is locked at the time that the
destructor runs, the behavior is undefined.
mutex::native_handlenative_handle_type native_handle();
The member function returns an object of type
native_handle_type that can be used in implementation-specific
ways.
mutex::native_handle_typetypedef h-type native_handle_type;
The typedef is a synonym for an implementation-specific type that can be used in implementation-specific ways.
In
this implementation,
it is a synonym for mtx_t, and can be used as an argument to any
of the mtx_XXX functions other than mtx_create.
mutex::try_lockbool try_lock();
The member function attempts to obtain ownership of the mutex without
blocking. If it succeeds it returns true. If it fails it returns
false. If the calling thread already owns the mutex, the behavior
is undefined.
mutex::unlockvoid unlock();
The member function releases ownership of the mutex. If the calling thread does not own the mutex, the behavior is undefined.
once_flagstruct once_flag
{
constexpr once_flag() noexcept;
once_flag(const once_flag&) = delete;
once_flag& operator=(const once_flag&) = delete;
};
The struct once_flag has only a default constructor. Objects
of type once_flag can be created but not copied. They are used
with the template function
call_once to ensure that
initialization code is called only once, even in the presence of multiple
threads of execution.
recursive_mutexlock
· recursive_mutex
· ~recursive_mutex
· native_handle
· native_handle_type
· try_lock
· unlock
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() noexcept;
void unlock();
typedef see below native_handle_type;
native_handle_type native_handle();
};
The class recursive_mutex is a
mutex type.
Objects of this type can be used to enforce mutual exclusion within
a program. Unlike objects of type mutex, the effect of calling
the various locking functions for objects of type recursive_mutex
that are already locked is well defined.
recursive_mutex::lockvoid lock();
The member function blocks the calling thread until the calling thread obtains ownership of the mutex. If the calling thread already owns the mutex, the function returns immediately and the previous lock remains in effect.
recursive_mutex::recursive_mutexrecursive_mutex();
The constructor constructs a recursive_mutex object that is not locked.
recursive_mutex::~recursive_mutex~recursive_mutex();
The destructor releases any resources used by the
recursive_mutex object. If the object is locked at the time that
the destructor runs, the behavior is undefined.
recursive_mutex::native_handlenative_handle_type native_handle();
The member function returns an object of type
native_handle_type that can be used in implementation-specific
ways.
recursive_mutex::native_handle_typetypedef h-type native_handle_type;
The typedef is a synonym for an implementation-specific type that can be used in implementation-specific ways.
In
this implementation,
it is a synonym for mtx_t, and can be used as an argument to any
of the mtx_XXX functions other than mtx_create.
recursive_mutex::try_lockbool try_lock() noexcept;
The member function attempts to obtain ownership of the mutex without
blocking. If it succeeds it returns true. If it fails it returns
false. If the calling thread already owns the mutex, the function
returns true immediately and the previous lock remains in
effect.
recursive_mutex::unlockvoid unlock();
The member function releases ownership of the mutex only after it has been
called as many times as lock or try_lock was
successfully called on the recursive_mutex object. If the calling thread does not own the mutex, the behavior is undefined.
recursive_timed_mutexlock
· recursive_timed_mutex
· ~recursive_timed_mutex
· native_handle
· native_handle_type
· try_lock
· try_lock_for
· try_lock_until
· unlock
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() noexcept;
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);
bool try_lock_until(const xtime *Abs_time);
void unlock();
typedef see below native_handle_type;
native_handle_type native_handle();
};
The class recursive_timed_mutex is a
timed mutex type. Objects of this type can be
used to enforce mutual exclusion with time-limited blocking within a program.
Unlike objects of type timed_mutex, the effect of calling the
various locking functions for objects of type
recursive_timed_mutex that are already locked is well
defined.
recursive_timed_mutex::lockvoid lock();
The member function blocks the calling thread until the calling thread obtains ownership of the mutex. If the calling thread already owns the mutex, the function returns immediately and the previous lock remains in effect.
recursive_timed_mutex::recursive_timed_mutexrecursive_timed_mutex();
The constructor constructs a recursive_timed_mutex object that
is not locked.
recursive_timed_mutex::~recursive_timed_mutex~recursive_timed_mutex();
The destructor releases any resources used by the
recursive_timed_mutex object. If the object is locked at the time
that the destructor runs, the behavior is undefined.
recursive_timed_mutex::native_handlenative_handle_type native_handle();
The member function returns an object of type
native_handle_type that can be used in implementation-specific
ways.
recursive_timed_mutex::native_handle_typetypedef h-type native_handle_type;
The typedef is a synonym for an implementation-specific type that can be used in implementation-specific ways.
In
this implementation,
it is a synonym for mtx_t, and can be used as an argument to any
of the mtx_XXX functions other than mtx_create.
recursive_timed_mutex::try_lockbool try_lock() noexcept;
The member function attempts to obtain ownership of the mutex without
blocking. If it succeeds it returns true. If it fails it returns
false. If the calling thread already owns the mutex, the function
returns true immediately and the previous lock remains in
effect.
recursive_timed_mutex::try_lock_fortemplate<class Rep, class Period>
bool try_lock_for(const chrono::duration<Rep, Period>& Rel_time);
The member function attempts to obtain ownership of the mutex without
blocking for longer than the time specified by Rel_time. If it
succeeds it returns true. If it fails it returns
false. If the calling thread already owns the mutex, the function
returns true immediately and the previous lock remains in
effect.
recursive_timed_mutex::try_lock_untiltemplate<class Clock, class Duration>
bool try_lock_until(const chrono::time_point<clock, Duration>& Abs_time);
bool try_lock_until(const xtime *Abs_time);
The first member function attempts to obtain ownership of the mutex without
blocking past the time specified by Abs_time. If it succeeds it
returns true. If it fails it returns false. If the
calling thread already owns the mutex, the function returns true
immediately and the previous lock remains in effect.
In
this implementation,
the second member function attempts to obtain ownership of the mutex without
blocking past the time specified by Abs_time. If it succeeds it
returns true. If it fails it returns false. If the
calling thread already owns the mutex, the function returns true
immediately and the previous lock remains in effect.
recursive_timed_mutex::unlockvoid unlock();
The member function releases ownership of the mutex only after it has been
called as many times as lock, try_lock,
try_lock_for, or try_lock_until was successfully
called on the recursive_timed_mutex object. If the calling thread
does not own the mutex, the behavior is undefined.
swaptemplate<class Mutex>
void swap(unique_lock<Mutex>& Left,
unique_lock<Mutex>& Right) noexcept;
Each template function calls Left.swap(Right).
timed_mutexlock
· timed_mutex
· ~timed_mutex
· native_handle
· native_handle_type
· try_lock
· try_lock_for
· try_lock_until
· unlock
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 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);
bool try_lock_until(const xtime *Abs_time);
void unlock();
typedef see below native_handle_type;
native_handle_type native_handle();
};
The class timed_mutex is a
timed mutex type. Objects of this type can be
used to enforce mutual exclusion with time-limited blocking within a
program.
timed_mutex::lockvoid lock();
The member function blocks the calling thread until the calling thread obtains ownership of the mutex. If the calling thread already owns the mutex, the behavior is undefined.
timed_mutex::timed_mutextimed_mutex();
The constructor constructs a timed_mutex object that is not locked.
timed_mutex::~timed_mutex~timed_mutex();
The destructor releases any resources used by the timed_mutex
object. If the object is locked at the time that the destructor runs, the
behavior is undefined.
timed_mutex::native_handlenative_handle_type native_handle();
The member function returns an object of type
native_handle_type that can be used in implementation-specific
ways.
timed_mutex::native_handle_typetypedef h-type native_handle_type;
The typedef is a synonym for an implementation-specific type that can be used in implementation-specific ways.
In
this implementation,
it is a synonym for mtx_t, and can be used as an argument to any
of the mtx_XXX functions other than mtx_create.
timed_mutex::try_lockbool try_lock();
The member function attempts to obtain ownership of the mutex without
blocking. If it succeeds it returns true. If it fails it returns
false. If the calling thread already owns the mutex, the behavior
is undefined.
timed_mutex::try_lock_fortemplate<class Rep, class Period>
bool try_lock_for(const chrono::duration<Rep, Period>& Rel_time);
The member function attempts to obtain ownership of the mutex without
blocking for longer than the time specified by Rel_time. If it
succeeds it returns true. If it fails it returns
false. If the calling thread already owns the mutex, the behavior
is undefined.
timed_mutex::try_lock_untiltemplate<class Clock, class Duration>
bool try_lock_until(const chrono::time_point<clock, Duration>& Abs_time);
bool try_lock_until(const xtime *Abs_time);
The first member function attempts to obtain ownership of the mutex without blocking past the time specified by Abs_time. If it
succeeds it returns true. If it fails it returns
false. If the calling thread already owns the mutex, the behavior
is undefined.
In
this implementation, the
second member function attempts to obtain ownership of the mutex without
blocking past the time specified by Abs_time. If it succeeds it
returns true. If it fails it returns false. If the
calling thread already owns the mutex, the behavior is undefined.
timed_mutex::unlockvoid unlock();
The member function releases ownership of the mutex. If the calling thread does not own the mutex, the behavior is undefined.
try_locktemplate<class L1, class L2, class... L3>
int try_lock(L1&, L2&, L3&...);
The arguments to the template function must be
mutex types, except that calls to try_lock may throw exceptions.
The function calls try_lock for each argument, from left to
right, until all the mutex objects have been locked or one of the calls to
try_lock fails. If one of the calls to try_lock
fails the function calls unlock on each of the mutex objects that
was locked. The function returns -1 if all the locks succeeded,
otherwise a non-negative value that is the 0-based index of the mutex object
that could not be locked.
try_to_lockconstexpr try_to_lock_t try_to_lock { };
The object can be passed to the constructor for unique_lock to
indicate that the constructor should try to lock the mutex object that is also
being passed to it without blocking.
try_to_lock_tstruct try_to_lock_t { };
The type is used to define an object, try_to_lock, that can be
used to select one of the overloaded constructors of
unique_lock.
unique_locklock
· mutex
· mutex_type
· operator bool
· operator=
· owns_lock
· release
· swap
· try_lock
· try_lock_for
· try_lock_until
· unique_lock
· ~unique_lock
· unlock
template<class Mutex>
class unique_lock
{
public:
typedef Mutex mutex_type;
// CONSTRUCT, ASSIGN, AND DESTROY
unique_lock() noexcept;
unique_lock(unique_lock&& Other) noexcept;
explicit unique_lock(mutex_type& m);
unique_lock(mutex_type& m, adopt_lock_t);
unique_lock(mutex_type& m, defer_lock_t) noexcept;
unique_lock(mutex_type& m, try_to_lock_t);
template<class Rep, class Period>
unique_lock(mutex_type& m,
const chrono::duration<Rep, Period>& Rel_time);
template<class Clock, class Duration>
unique_lock(mutex_type& m,
const chrono::time_point<Clock, Duration>& Abs_time);
unique_lock(mutex_type& m,
const xtime *Abs_time);
unique_lock(unique_lock&&) noexcept;
unique_lock(const unique_lock&) = delete;
unique_lock& operator=(const unique_lock&) = delete;
unique_lock& operator=(unique_lock&&) noexcept;
~unique_lock();
// LOCK AND UNLOCK
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);
bool try_lock_until(const xtime *Abs_time);
void unlock();
// MUTATE
void swap(unique_lock& Other) noexcept;
mutex_type *release() noexcept;
// OBSERVE
bool owns_lock() const noexcept;
explicit operator bool() const noexcept;
mutex_type *mutex() const noexcept;
private:
mutex *pmtx; // exposition only
bool owns; // exposition only
};
The template can be instantiated to create objects that manage locking and
unlocking of a mutex. The template argument Mutex must name a
mutex type.
unique_lock::lockvoid lock();
If pmtx is a null pointer, the function throws an object of
type system_error with an error code of
operation_not_permitted. If owns == true, the
function throws an object of type system_error with an error
code of resource_deadlock_would_occur. Otherwise, the member
function calls pmtx->lock() and sets owns to
true.
unique_lock::mutexmutex_type *mutex() const noexcept;
The member function returns pmtx.
unique_lock::mutex_typetypedef Mutex mutex_type;
The typedef name is a synonym for the template argument
Mutex.
unique_lock::operator boolexplicit operator bool() noexcept;
The member function returns owns.
unique_lock::operator=unique_lock& operator=(unique_lock&& Other) noexcept;
If owns, calls pmtx->unlock(). Copies
pmtx and owns from Other into
*this then sets Other to a default-constructed
state.
unique_lock::owns_lockbool owns_lock() const noexcept;
The member function returns owns.
unique_lock::releasemutex_type *release() noexcept;
The member function sets pmtx to 0 and
owns to false. It returns the previous value of
pmtx.
unique_lock::swapvoid swap(unique_lock&& Other) noexcept;
The member function swaps the values of pmtx and owns
in Other and *this.
unique_lock::try_lockbool try_lock();
If pmtx is a null pointer, the function throws an object of
type system_error with an error code of
operation_not_permitted. If owns == true, the
function throws an object of type system_error with an error
code of resource_deadlock_would_occur. Otherwise, the member
function calls pmtx->try_lock() and assigns the result to
owns. It returns the new value of owns.
unique_lock::try_lock_fortemplate<class Rep, class Period>
bool try_lock_for(const chrono::duration<Rep, Period>& Rel_time);
If pmtx is a null pointer, the function throws an object of
type system_error with an error code of
operation_not_permitted. If owns == true, the
function throws an object of type system_error with an error
code of resource_deadlock_would_occur. Otherwise, the member
function calls pmtx->try_lock_for(Rel_time) and assigns the
result to owns. It returns the new value of
owns.
unique_lock::try_lock_untiltemplate<class Clock, class Duration>
bool try_lock_until(const chrono::time_point<Clock, Duration>& Abs_time);
bool try_lock_until(const xtime *Abs_time);
If pmtx is a null pointer, the member functions throw an
object of type system_error with an error code of
operation_not_permitted. If owns == true, the
functions throw an object of type system_error with an error
code of resource_deadlock_would_occur.
The first member function calls pmtx->try_lock_until(Abs_time)
and assigns the result to owns. It returns the new value of
owns.
In
this implementation,
the second member function calls pmtx->try_lock_until(Abs_time)
and assigns the result to owns. It returns the new value of
owns.
unique_lock::unique_lockunique_lock() noexcept;
unique_lock(unique_lock&& Other) noexcept;
explicit unique_lock(mutex_type& mtx);
unique_lock(mutex_type& mtx, adopt_lock_t Adopt);
unique_lock(mutex_type& mtx, defer_lock_t Defer) noexcept;
unique_lock(mutex_type& mtx, try_to_lock_t Try);
template<class Rep, class Period>
unique_lock(mutex_type& mtx,
const chrono::duration<Rep, Period> Rel_time);
template<class Clock, class Duration>
unique_lock(mutex_type& mtx,
const chrono::time_point<Clock, Duration> Abs_time);
unique_lock(mutex_type& mtx,
const xtime *Abs_time) noexcept;
The first constructor constructs an object with pmtx equal to
0 and owns equal to false.
The second constructor constructs an object with pmtx equal to
Other.pmtx and owns equal to Other.owns
and then sets Other.pmtx to 0 and
Other.owns to false.
The remaining constructors all construct an object with pmtx
set to &mtx. They set their stored value owns
either to a particular value or to the result of a function call, depending on
their second argument, as follows:
owns = true and calls pmtx->lock()Adopt -- owns = true. mtx
must be locked when the constructor is called. The constructor throws nothing.Defer -- owns = false. mtx
must not be locked when the constructor is called.Try -- owns = pmtx->try_lock().
The constructor throws nothing.Rel_time -- owns = pmtx->try_lock_for(Rel_time).Abs_time -- owns = pmtx->try_lock_until(Abs_time).unique_lock::~unique_lock~unique_lock();
Calls pmtx->lock() if owns is true.
unique_lock::unlockvoid unlock();
If owns == false, the function throws an object of type
system_error with an error code of
operation_not_permitted. Otherwise,
the member function calls pmtx->unlock() and sets
owns to false.
A mutex type satisfies the following requirements:
lock, try_lock, and
unlock, as described below.The required member functions must be callable with no arguments. A mutex type can define them with additional arguments, provided those additional arguments all have default values.
lock
The member function blocks the calling thread until the calling thread obtains ownership of the mutex. Its return value, if any, is ignored.
try_lock
The member function attempts to obtain ownership of the mutex, without
blocking. It returns a type that is convertible to bool. It
returns a value that converts to true if it obtains ownership,
otherwise to false.
unlock
The member function releases the calling thread's ownership of the mutex.
A
timed mutex type satisfies the
requirements for a mutex type. In addition, it has member functions
try_lock_for and try_lock_until. These member
functions must be callable with one argument and return a type that is
convertible to bool, as described below. A timed mutex type can
define these functions with additional arguments, provided those additional
arguments all have default values.
try_lock_for
The member function must be callable with a single argument,
Rel_time, whose type is an instantiation of the template
chrono::duration. It attempts to
obtain ownership of the mutex, but will return within the time designated by
Rel_time even if it does not obtain ownership. It returns a value
that converts to true if it obtains ownership, otherwise to
false.
try_lock_until
The member function must be callable with a single argument,
Abs_time, whose type is an instantiation of the template
chrono::time_point. It attempts to
obtain ownership of the mutex, but will return no later than the time
designated by Abs_time even if it does not obtain ownership. It
returns a value that converts to true if it obtains ownership,
otherwise to false.
A mutex type is also known as a lockable type.
If it does not provide the member function try_lock, it is
a basic lockable type.
A timed mutex type is also known as a
timed lockable type.
See also the Table of Contents and the Index.
Copyright © 1992-2013 by P.J. Plauger. All rights reserved.