You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
213 lines
4.9 KiB
C++
213 lines
4.9 KiB
C++
/*
|
|
* yamc_shared_lock.hpp
|
|
*
|
|
* MIT License
|
|
*
|
|
* Copyright (c) 2017 yohhoy
|
|
*
|
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
* of this software and associated documentation files (the "Software"), to deal
|
|
* in the Software without restriction, including without limitation the rights
|
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
* copies of the Software, and to permit persons to whom the Software is
|
|
* furnished to do so, subject to the following conditions:
|
|
*
|
|
* The above copyright notice and this permission notice shall be included in all
|
|
* copies or substantial portions of the Software.
|
|
*
|
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
* SOFTWARE.
|
|
*/
|
|
#ifndef YAMC_SHARED_LOCK_HPP_
|
|
#define YAMC_SHARED_LOCK_HPP_
|
|
|
|
#include <cassert>
|
|
#include <chrono>
|
|
#include <mutex>
|
|
#include <system_error>
|
|
#include <utility> // std::swap
|
|
|
|
|
|
/*
|
|
* std::shared_lock in C++14 Standard Library
|
|
*
|
|
* - yamc::shared_lock<Mutex>
|
|
*/
|
|
namespace yamc {
|
|
|
|
template <typename Mutex>
|
|
class shared_lock {
|
|
void locking_precondition(const char* emsg)
|
|
{
|
|
if (pm_ == nullptr) {
|
|
throw std::system_error(std::make_error_code(std::errc::operation_not_permitted), emsg);
|
|
}
|
|
if (owns_) {
|
|
throw std::system_error(std::make_error_code(std::errc::resource_deadlock_would_occur), emsg);
|
|
}
|
|
}
|
|
|
|
public:
|
|
using mutex_type = Mutex;
|
|
|
|
shared_lock() noexcept = default;
|
|
|
|
explicit shared_lock(mutex_type& m)
|
|
{
|
|
m.lock_shared();
|
|
pm_ = &m;
|
|
owns_ = true;
|
|
}
|
|
|
|
shared_lock(mutex_type& m, std::defer_lock_t) noexcept
|
|
{
|
|
pm_ = &m;
|
|
owns_ = false;
|
|
}
|
|
|
|
shared_lock(mutex_type& m, std::try_to_lock_t)
|
|
{
|
|
pm_ = &m;
|
|
owns_ = m.try_lock_shared();
|
|
}
|
|
|
|
shared_lock(mutex_type& m, std::adopt_lock_t)
|
|
{
|
|
pm_ = &m;
|
|
owns_ = true;
|
|
}
|
|
|
|
template <typename Clock, typename Duration>
|
|
shared_lock(mutex_type& m, const std::chrono::time_point<Clock, Duration>& abs_time)
|
|
{
|
|
pm_ = &m;
|
|
owns_ = m.try_lock_shared_until(abs_time);
|
|
}
|
|
|
|
template <typename Rep, typename Period>
|
|
shared_lock(mutex_type& m, const std::chrono::duration<Rep, Period>& rel_time)
|
|
{
|
|
pm_ = &m;
|
|
owns_ = m.try_lock_shared_for(rel_time);
|
|
}
|
|
|
|
~shared_lock()
|
|
{
|
|
if (owns_) {
|
|
assert(pm_ != nullptr);
|
|
pm_->unlock_shared();
|
|
}
|
|
}
|
|
|
|
shared_lock(const shared_lock&) = delete;
|
|
shared_lock& operator=(const shared_lock&) = delete;
|
|
|
|
shared_lock(shared_lock&& rhs) noexcept
|
|
{
|
|
if (pm_ && owns_) {
|
|
pm_->unlock_shared();
|
|
}
|
|
pm_ = rhs.pm_;
|
|
owns_ = rhs.owns_;
|
|
rhs.pm_ = nullptr;
|
|
rhs.owns_ = false;
|
|
}
|
|
|
|
shared_lock& operator=(shared_lock&& rhs) noexcept
|
|
{
|
|
if (pm_ && owns_) {
|
|
pm_->unlock_shared();
|
|
}
|
|
pm_ = rhs.pm_;
|
|
owns_ = rhs.owns_;
|
|
rhs.pm_ = nullptr;
|
|
rhs.owns_ = false;
|
|
return *this;
|
|
}
|
|
|
|
void lock()
|
|
{
|
|
locking_precondition("shared_lock::lock");
|
|
pm_->lock_shared();
|
|
owns_ = true;
|
|
}
|
|
|
|
bool try_lock()
|
|
{
|
|
locking_precondition("shared_lock::try_lock");
|
|
return (owns_ = pm_->try_lock_shared());
|
|
}
|
|
|
|
template <typename Rep, typename Period>
|
|
bool try_lock_for(const std::chrono::duration<Rep, Period>& rel_time)
|
|
{
|
|
locking_precondition("shared_lock::try_lock_for");
|
|
return (owns_ = pm_->try_lock_shared_for(rel_time));
|
|
}
|
|
|
|
template <typename Clock, typename Duration>
|
|
bool try_lock_until(const std::chrono::time_point<Clock, Duration>& abs_time)
|
|
{
|
|
locking_precondition("shared_lock::try_lock_until");
|
|
return (owns_ = pm_->try_lock_shared_until(abs_time));
|
|
}
|
|
|
|
void unlock()
|
|
{
|
|
assert(pm_ != nullptr);
|
|
if (!owns_) {
|
|
throw std::system_error(std::make_error_code(std::errc::operation_not_permitted), "shared_lock::unlock");
|
|
}
|
|
pm_->unlock_shared();
|
|
owns_ = false;
|
|
}
|
|
|
|
void swap(shared_lock& sl) noexcept
|
|
{
|
|
std::swap(pm_, sl.pm_);
|
|
std::swap(owns_, sl.owns_);
|
|
}
|
|
|
|
mutex_type* release() noexcept
|
|
{
|
|
mutex_type* result = pm_;
|
|
pm_ = nullptr;
|
|
owns_ = false;
|
|
return result;
|
|
}
|
|
|
|
bool owns_lock() const noexcept
|
|
{ return owns_; }
|
|
|
|
explicit operator bool() const noexcept
|
|
{ return owns_; }
|
|
|
|
mutex_type* mutex() const noexcept
|
|
{ return pm_; }
|
|
|
|
private:
|
|
mutex_type* pm_ = nullptr;
|
|
bool owns_ = false;
|
|
};
|
|
|
|
} // namespace yamc
|
|
|
|
|
|
namespace std {
|
|
|
|
/// std::swap() specialization for yamc::shared_lock<Mutex> type
|
|
template <typename Mutex>
|
|
void swap(yamc::shared_lock<Mutex>& lhs, yamc::shared_lock<Mutex>& rhs) noexcept
|
|
{
|
|
lhs.swap(rhs);
|
|
}
|
|
|
|
} // namespace std
|
|
|
|
#endif
|