/* * 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 #include #include #include #include // std::swap /* * std::shared_lock in C++14 Standard Library * * - yamc::shared_lock */ namespace yamc { template 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(const mutex_type& m, std::defer_lock_t) noexcept { pm_ = &m; owns_ = false; } shared_lock(const mutex_type& m, std::try_to_lock_t) { pm_ = &m; owns_ = m.try_lock_shared(); } shared_lock(const mutex_type& m, std::adopt_lock_t) { pm_ = &m; owns_ = true; } template shared_lock(const mutex_type& m, const std::chrono::time_point& abs_time) { pm_ = &m; owns_ = m.try_lock_shared_until(abs_time); } template shared_lock(const mutex_type& m, const std::chrono::duration& 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 bool try_lock_for(const std::chrono::duration& rel_time) { locking_precondition("shared_lock::try_lock_for"); return (owns_ = pm_->try_lock_shared_for(rel_time)); } template bool try_lock_until( const std::chrono::time_point& 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 type template void swap(yamc::shared_lock& lhs, yamc::shared_lock& rhs) noexcept { lhs.swap(rhs); } } // namespace std #endif