32 #ifndef _UTILS_SHARED_MUTEX_HPP_
33 #define _UTILS_SHARED_MUTEX_HPP_
36 #include <condition_variable>
39 #include <system_error>
57 typedef std::condition_variable
cond_t;
76 std::lock_guard<mutex_t> _(
mut_);
88 std::lock_guard<mutex_t> _(
mut_);
99 std::lock_guard<mutex_t> _(
mut_);
108 std::unique_lock<mutex_t> lk(
mut_);
120 std::lock_guard<mutex_t> _(
mut_);
134 template<shared_mutex_type>
149 std::unique_lock<mutex_t> lk(mut_);
150 while (state_ & write_entered_)
154 state_ |= write_entered_;
155 while (state_ & n_readers_)
163 std::lock_guard<mutex_t> _(mut_);
164 count_t num_readers = (state_ & n_readers_) - 1;
165 state_ &= ~n_readers_;
166 state_ |= num_readers;
167 if (state_ & write_entered_)
169 if (num_readers == 0)
174 else if (num_readers == n_readers_ - 1)
188 count_t writer_waiting_ = 0;
194 std::unique_lock<mutex_t> lk(mut_);
196 while (state_ & n_readers_ || state_ & write_entered_)
200 state_ |= write_entered_;
206 std::lock_guard<mutex_t> _(mut_);
207 count_t num_readers = (state_ & n_readers_) - 1;
208 state_ &= ~n_readers_;
209 state_ |= num_readers;
211 if ((writer_waiting_ && num_readers == 0)
212 || (num_readers == n_readers_ - 1))
226 std::thread::id exclusive_owner_ = {};
228 std::map<std::thread::id, unsigned int> shared_owners_;
234 std::lock_guard<std::mutex> _(wm_);
242 std::lock_guard<std::mutex> _(wm_);
243 exclusive_owner_ = std::this_thread::get_id();
248 bool res = sm::try_lock();
249 std::lock_guard<std::mutex> _(wm_);
252 exclusive_owner_ = std::this_thread::get_id();
260 std::lock_guard<std::mutex> _(wm_);
261 exclusive_owner_ = std::thread::id();
269 std::lock_guard<std::mutex> _(wm_);
270 ++shared_owners_[std::this_thread::get_id()];
275 bool res = sm::try_lock_shared();
276 std::lock_guard<std::mutex> _(wm_);
279 ++shared_owners_[std::this_thread::get_id()];
287 std::lock_guard<std::mutex> _(wm_);
288 auto owner = shared_owners_.find(std::this_thread::get_id());
289 if ( owner != shared_owners_.end() && 0 == --owner->second )
291 shared_owners_.erase(owner);
300 #if defined(__has_include) && __has_include(<version>)
302 #endif // if defined(__has_include) && __has_include(<version>)
305 #if defined(__has_include) && __has_include(<version>) && !defined(__cpp_lib_shared_mutex) || \
307 ( !(defined(__has_include) && __has_include(<version>)) && \
308 !(defined(HAVE_CXX17) && HAVE_CXX17) && __cplusplus < 201703 )
312 template <
class Mutex>
357 , owns_(m.try_lock_shared())
369 template <
class Clock,
class Duration>
372 const std::chrono::time_point<Clock, Duration>& abs_time)
374 , owns_(m.try_lock_shared_until(abs_time))
378 template <
class Rep,
class Period>
381 const std::chrono::duration<Rep, Period>& rel_time)
383 , owns_(m.try_lock_shared_for(rel_time))
405 sl.m_ =
nullptr; sl.owns_ =
false;
423 std::unique_lock<mutex_type>&& ul)
429 m_->unlock_and_lock_shared();
436 template <
class Rep,
class Period>
438 const std::chrono::duration<Rep, Period>& rel_time)
440 return try_lock_until(std::chrono::steady_clock::now() + rel_time);
443 template <
class Clock,
class Duration>
446 const std::chrono::time_point<Clock, Duration>& abs_time);
453 std::swap(owns_, u.owns_);
469 operator int __nat::* ()
const {
470 return owns_ ? &__nat::_ : 0;
479 template <
class Mutex>
485 throw std::system_error(std::error_code(EPERM, std::system_category()),
486 "shared_lock::lock: references null mutex");
490 throw std::system_error(std::error_code(EDEADLK, std::system_category()),
491 "shared_lock::lock: already locked");
497 template <
class Mutex>
503 throw std::system_error(std::error_code(EPERM, std::system_category()),
504 "shared_lock::try_lock: references null mutex");
508 throw std::system_error(std::error_code(EDEADLK, std::system_category()),
509 "shared_lock::try_lock: already locked");
511 owns_ = m_->try_lock_shared();
515 template <
class Mutex>
516 template <
class Clock,
class Duration>
519 const std::chrono::time_point<Clock, Duration>& abs_time)
523 throw std::system_error(std::error_code(EPERM, std::system_category()),
524 "shared_lock::try_lock_until: references null mutex");
528 throw std::system_error(std::error_code(EDEADLK, std::system_category()),
529 "shared_lock::try_lock_until: already locked");
531 owns_ = m_->try_lock_shared_until(abs_time);
535 template <
class Mutex>
541 throw std::system_error(std::error_code(EPERM, std::system_category()),
542 "shared_lock::unlock: not locked");
548 template <
class Mutex>
560 #else // fallback to STL
562 #include <shared_mutex>
566 using std::shared_lock;
571 #endif // shared_lock selection
573 #ifndef USE_THIRDPARTY_SHARED_MUTEX
574 # if defined(_MSC_VER) && _MSVC_LANG < 202302L
575 # pragma message("warning: USE_THIRDPARTY_SHARED_MUTEX not defined. By default use framework version.")
577 # warning "USE_THIRDPARTY_SHARED_MUTEX not defined. By default use framework version."
578 # endif // if defined(_MSC_VER) && _MSVC_LANG < 202302L
579 # define USE_THIRDPARTY_SHARED_MUTEX 0
580 #endif // ifndef USE_THIRDPARTY_SHARED_MUTEX
583 #if defined(__has_include) && __has_include(<version>) && !defined(__cpp_lib_shared_mutex) || \
585 (~USE_THIRDPARTY_SHARED_MUTEX + 1) || \
587 ( !(defined(__has_include) && __has_include(<version>)) && \
588 !(defined(HAVE_CXX17) && HAVE_CXX17) && __cplusplus < 201703 )
635 using shared_mutex = detail::shared_mutex<detail::shared_mutex_type::PTHREAD_RWLOCK_PREFER_READER_NP>;
643 #else // fallback to STL
645 #include <shared_mutex>
649 using std::shared_mutex;
653 #endif // shared_mutex selection
655 #endif // _UTILS_SHARED_MUTEX_HPP_