shared_lock.hpp 2.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131
  1. #ifndef BOOST_COMPAT_SHARED_LOCK_HPP_INCLUDED
  2. #define BOOST_COMPAT_SHARED_LOCK_HPP_INCLUDED
  3. // Copyright 2023 Christian Mazakas.
  4. // Distributed under the Boost Software License, Version 1.0.
  5. // https://www.boost.org/LICENSE_1_0.txt
  6. #include <boost/compat/detail/throw_system_error.hpp>
  7. #include <memory> // std::addressof
  8. #include <mutex> // std::defer_lock_t
  9. #include <system_error> // std::errc
  10. namespace boost {
  11. namespace compat {
  12. template <class Mutex>
  13. class shared_lock;
  14. template <class Mutex>
  15. void swap( shared_lock<Mutex>& x, shared_lock<Mutex>& y ) noexcept;
  16. template <class Mutex>
  17. class shared_lock {
  18. private:
  19. Mutex* pm_ = nullptr;
  20. bool owns_ = false;
  21. public:
  22. using mutex_type = Mutex;
  23. shared_lock() noexcept = default;
  24. explicit shared_lock( mutex_type& m ) : pm_( std::addressof( m ) ) { lock(); }
  25. shared_lock( mutex_type& m, std::defer_lock_t ) noexcept
  26. : pm_( std::addressof( m ) ) {}
  27. shared_lock( mutex_type& m, std::try_to_lock_t )
  28. : pm_( std::addressof( m ) ) {
  29. try_lock();
  30. }
  31. shared_lock( mutex_type& m, std::adopt_lock_t )
  32. : pm_( std::addressof( m ) ), owns_{ true } {}
  33. ~shared_lock() {
  34. if ( owns_ ) {
  35. unlock();
  36. }
  37. }
  38. shared_lock( const shared_lock& ) = delete;
  39. shared_lock& operator=( const shared_lock& ) = delete;
  40. shared_lock( shared_lock&& u ) noexcept {
  41. pm_ = u.pm_;
  42. owns_ = u.owns_;
  43. u.pm_ = nullptr;
  44. u.owns_ = false;
  45. }
  46. shared_lock& operator=( shared_lock&& u ) noexcept {
  47. shared_lock( std::move( u ) ).swap( *this );
  48. return *this;
  49. }
  50. void lock() {
  51. if ( !pm_ ) {
  52. detail::throw_system_error( std::errc::operation_not_permitted );
  53. }
  54. if ( owns_lock() ) {
  55. detail::throw_system_error( std::errc::resource_deadlock_would_occur );
  56. }
  57. pm_->lock_shared();
  58. owns_ = true;
  59. }
  60. bool try_lock() {
  61. if ( !pm_ ) {
  62. detail::throw_system_error( std::errc::operation_not_permitted );
  63. }
  64. if ( owns_lock() ) {
  65. detail::throw_system_error( std::errc::resource_deadlock_would_occur );
  66. }
  67. bool b = pm_->try_lock_shared();
  68. owns_ = b;
  69. return b;
  70. }
  71. void unlock() {
  72. if ( !pm_ || !owns_ ) {
  73. detail::throw_system_error( std::errc::operation_not_permitted );
  74. }
  75. pm_->unlock_shared();
  76. owns_ = false;
  77. }
  78. void swap( shared_lock& u ) noexcept {
  79. std::swap( pm_, u.pm_ );
  80. std::swap( owns_, u.owns_ );
  81. }
  82. mutex_type* release() noexcept {
  83. mutex_type* pm = pm_;
  84. pm_ = nullptr;
  85. owns_ = false;
  86. return pm;
  87. }
  88. mutex_type* mutex() const noexcept { return pm_; }
  89. bool owns_lock() const noexcept { return owns_; }
  90. explicit operator bool() const noexcept { return owns_; }
  91. };
  92. template <class Mutex>
  93. void swap( shared_lock<Mutex>& x, shared_lock<Mutex>& y ) noexcept {
  94. x.swap( y );
  95. }
  96. } // namespace compat
  97. } // namespace boost
  98. #endif // BOOST_COMPAT_SHARED_LOCK_HPP_INCLUDED