////
Copyright 2023 Christian Mazakas
Distributed under the Boost Software License, Version 1.0.
https://www.boost.org/LICENSE_1_0.txt
////
[#shared_lock]
# <boost/compat/shared_lock.hpp>
:idprefix: ref_shared_lock_
## Description
The header `<boost/compat/shared_lock.hpp>` implements, in a portable way, the C++14
`std::shared_lock` class template.
The class `shared_lock` is a RAII wrapper that manages locking and unlocking
the provided Mutex, provided that it implements https://en.cppreference.com/w/cpp/named_req/SharedLockable[SharedLockable].
This is the shared analog of https://en.cppreference.com/w/cpp/thread/unique_lock[unique_lock]
and calls `lock_shared()` instead of `lock()`.
## Example
```cpp
#include <boost/compat/shared_lock.hpp>
shared_mutex m;
// acquire the lock by calling `m.lock_shared()`
// `m.unlock_shared()` is called automatically for us by `guard` now
boost::compat::shared_lock<shared_mutex> guard(m);
assert(guard.owns_lock());
```
## Synopsis
```cpp
namespace boost {
namespace compat {
template <class Mutex>
class shared_lock;
template <class Mutex>
void swap( shared_lock<Mutex>& x, shared_lock<Mutex>& y ) noexcept;
template <class Mutex>
class shared_lock {
using mutex_type = Mutex;
shared_lock() noexcept = default;
explicit shared_lock( mutex_type& m );
shared_lock( mutex_type& m, std::defer_lock_t ) noexcept;
shared_lock( mutex_type& m, std::try_lock_t );
shared_lock( mutex_type& m, std::adopt_lock_t );
~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();
void unlock();
void swap( shared_lock& u ) noexcept;
mutex_type* release() noexcept;
mutex_type* mutex() const noexcept;
bool owns_lock() const noexcept;
explicit operator bool() const noexcept;
};
} // namespace compat
} // namespace boost
```
## Constructors
### Default Constructor
```cpp
shared_lock() noexcept = default;
```
[horizontal]
Postconditions:;; `mutex() == nullptr` and `owns_lock() == false`.
### Locking Constructor
```cpp
explicit shared_lock( mutex_type& m );
```
[horizontal]
Effects:;; Calls `m.lock_shared()`.
Postconditions:;; `mutex() == std::addressof(m)` and `owns_lock() == true`.
### Deferred Constructor
```cpp
shared_lock( mutex_type& m, std::defer_lock_t ) noexcept;
```
[horizontal]
Postconditions:;; `mutex() == std::addressof(m)` and `owns_lock() == false`.
### Try-to-Lock Constructor
```cpp
shared_lock( mutex_type& m, std::try_lock_t );
```
[horizontal]
Effects:;; Calls `m.try_lock_shared()`.
Postconditions:;; `mutex() == std::addressof(m)` and `owns_lock() == res` where
`res` is the result of the `m.try_lock_shared()` call.
### Adopting Constructor
```cpp
shared_lock( mutex_type& m, std::adopt_lock_t );
```
[horizontal]
Preconditions:;; `m` must be held by a previous call to `m.lock_shared()` or a
successful call to `m.try_lock_shared()`.
Postconditions:;; `mutex() == std::addressof(m)` and `owns_lock() == true`.
### Copy Constructor
```cpp
shared_lock( const shared_lock& ) = delete;
```
`shared_lock` is not copyable.
### Move Constructor
```cpp
shared_lock( shared_lock&& u ) noexcept;
```
[horizontal]
Postconditions:;; `mutex() == s.mutex()` and `owns_lock() == s.owns_lock()` where
`s` is the state of `u` before move. `u.mutex() == nullptr` and `u.owns_lock() == false`
after move.
## Assignment
### Copy Assignment
```cpp
shared_lock& operator=( const shared_lock& ) = delete;
```
`shared_lock` is not copyable.
### Move Assignment
```cpp
shared_lock& operator=( shared_lock&& u ) noexcept;
```
[horizontal]
Effects:;; If `owns_lock() == true`, calls `unlock()`.
Postconditions:;; `mutex() == s.mutex()` and `owns_lock() == s.owns_lock()` where
`s` is the state of `u` before move. `u.mutex() == nullptr` and `u.owns_lock() == false`
after move.
## Destructor
```cpp
~shared_lock();
```
[horizontal]
Effects:;; If `owns_lock() == true`, calls `unlock()`.
## Member Functions
### Locking
#### lock
```cpp
void lock();
```
[horizontal]
Effects:;; Calls `mutex()\->lock_shared()`.
Postconditions:;; `owns_lock() == true`.
Throws:;; Any exception caused by `mutex()\->lock_shared()`. `std::system_error`
when `mutex() == nullptr` (with `std::errc::operation_not_permitted`) or
`owns_lock() == true` (with `std::errc::resource_deadlock_would_occur`).
#### try_lock
```cpp
bool try_lock();
```
[horizontal]
Effects:;; Calls `mutex()\->try_lock_shared()`.
Postconditions:;; `owns_lock() == res` where `res = mutex()\->try_lock_shared()`.
Throws:;; Any exception caused by `mutex()\->try_lock_shared()`. `std::system_error`
when `mutex() == nullptr` (with `std::errc::operation_not_permitted`) or
`owns_lock() == true` (with `std::errc::resource_deadlock_would_occur`).
#### unlock
```cpp
void unlock();
```
[horizontal]
Effects:;; Calls `mutex()\->unlock_shared()`.
Postconditions:;; `owns_lock() == false`.
Throws:;; `std::system_error` (with `std::errc::operation_not_permitted`) if `owns_lock() == false`.
### Modifiers
#### swap
```cpp
void swap( shared_lock& u ) noexcept;
```
[horizontal]
Effects:;; Swaps the data members of `*this` and `u`.
#### release
```cpp
mutex_type* release() noexcept;
```
[horizontal]
Postconditions:;; `mutex() == nullptr` and `owns_lock() == false`.
Returns:;; The previous value of `mutex()`.
#### Free Function swap
```cpp
template <class Mutex>
void swap( shared_lock<Mutex>& x, shared_lock<Mutex>& y ) noexcept;
```
[horizontal]
Effects:;; Swaps the data members of `x` and `y` via `x.swap(y)`.
### Observers
#### mutex
```cpp
mutex_type* mutex() const noexcept;
```
[horizontal]
Returns:;; The value of the internal pointer, either `nullptr` or the address of
the mutex.
#### owns_lock
```cpp
bool owns_lock() const noexcept;
```
[horizontal]
Returns:;; A boolean indicating whether or not the mutex is locked by the current
`shared_lock` instance.
#### boolean conversion
```cpp
explicit operator bool() const noexcept;
```
[horizontal]
Returns:;; A boolean indicating whether or not the mutex is locked by the current
`shared_lock` instance.