1 /*
2 * Distributed under the Boost Software License, Version 1.0.
3 * (See accompanying file LICENSE_1_0.txt or copy at
4 * http://www.boost.org/LICENSE_1_0.txt)
5 *
6 * (C) Copyright 2007 Anthony Williams
7 * (C) Copyright 2011-2012 Vicente J. Botet Escriba
8 * (C) Copyright 2013 Andrey Semashev
9 */
10 /*!
11 * \file locks/shared_lock.hpp
12 *
13 * \brief This header defines a shared lock guard.
14 */
15
16 #ifndef BOOST_SYNC_LOCKS_SHARED_LOCK_HPP_INCLUDED_
17 #define BOOST_SYNC_LOCKS_SHARED_LOCK_HPP_INCLUDED_
18
19 #include <cstddef>
20 #include <boost/move/core.hpp>
21 #include <boost/move/utility.hpp>
22 #include <boost/utility/enable_if.hpp>
23 #include <boost/utility/explicit_operator_bool.hpp>
24 #include <boost/sync/detail/config.hpp>
25 #include <boost/sync/detail/time_traits.hpp>
26 #include <boost/sync/detail/throw_exception.hpp>
27 #include <boost/sync/detail/system_error.hpp>
28 #include <boost/sync/exceptions/lock_error.hpp>
29 #include <boost/sync/locks/lock_options.hpp>
30 #include <boost/sync/locks/shared_lock_fwd.hpp>
31 #if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES)
32 #include <boost/sync/locks/unique_lock_fwd.hpp>
33 #include <boost/sync/locks/upgrade_lock_fwd.hpp>
34 #else
35 // These locks need to be defined for Boost.Move emulation
36 #include <boost/sync/locks/unique_lock.hpp>
37 #include <boost/sync/locks/upgrade_lock.hpp>
38 #endif
39
40 #include <boost/sync/detail/header.hpp>
41
42 #ifdef BOOST_HAS_PRAGMA_ONCE
43 #pragma once
44 #endif
45
46 namespace boost {
47
48 namespace sync {
49
50 /*!
51 * \brief A shared lock scope guard
52 */
53 template< typename Mutex >
54 class shared_lock
55 {
56 public:
57 typedef Mutex mutex_type;
58
59 private:
60 mutex_type* m_mutex;
61 bool m_is_locked;
62
63 public:
64 BOOST_MOVABLE_BUT_NOT_COPYABLE(shared_lock)
65
66 public:
shared_lock()67 shared_lock() BOOST_NOEXCEPT :
68 m_mutex(NULL), m_is_locked(false)
69 {
70 }
71
shared_lock(mutex_type & m)72 explicit shared_lock(mutex_type& m) :
73 m_mutex(&m), m_is_locked(false)
74 {
75 lock();
76 }
shared_lock(mutex_type & m,adopt_lock_t)77 shared_lock(mutex_type& m, adopt_lock_t) BOOST_NOEXCEPT :
78 m_mutex(&m), m_is_locked(true)
79 {
80 }
shared_lock(mutex_type & m,defer_lock_t)81 shared_lock(mutex_type& m, defer_lock_t) BOOST_NOEXCEPT :
82 m_mutex(&m), m_is_locked(false)
83 {
84 }
shared_lock(mutex_type & m,try_to_lock_t)85 shared_lock(mutex_type& m, try_to_lock_t) :
86 m_mutex(&m), m_is_locked(false)
87 {
88 try_lock();
89 }
90
91 template< typename Time >
shared_lock(typename enable_if_c<detail::time_traits<Time>::is_specialized,mutex_type &>::type m,Time const & t)92 shared_lock(typename enable_if_c< detail::time_traits< Time >::is_specialized, mutex_type& >::type m, Time const& t) :
93 m_mutex(&m), m_is_locked(false)
94 {
95 timed_lock(t);
96 }
97
shared_lock(BOOST_RV_REF (shared_lock)that)98 shared_lock(BOOST_RV_REF(shared_lock) that) BOOST_NOEXCEPT :
99 m_mutex(that.m_mutex), m_is_locked(that.m_is_locked)
100 {
101 that.m_mutex = NULL;
102 that.m_is_locked = false;
103 }
104
105 // Conversion from unique locking
shared_lock(BOOST_RV_REF (unique_lock<mutex_type>)that)106 explicit shared_lock(BOOST_RV_REF(unique_lock< mutex_type >) that) :
107 m_mutex(that.m_mutex), m_is_locked(that.m_is_locked)
108 {
109 if (m_is_locked)
110 m_mutex->unlock_and_lock_shared();
111 that.release();
112 }
113
shared_lock(BOOST_RV_REF (upgrade_lock<mutex_type>)that)114 explicit shared_lock(BOOST_RV_REF(upgrade_lock< mutex_type >) that) :
115 m_mutex(that.m_mutex), m_is_locked(that.m_is_locked)
116 {
117 if (m_is_locked)
118 m_mutex->unlock_upgrade_and_lock_shared();
119 that.release();
120 }
121
~shared_lock()122 ~shared_lock()
123 {
124 if (m_is_locked)
125 m_mutex->unlock_shared();
126 }
127
operator =(BOOST_RV_REF (shared_lock)that)128 shared_lock& operator= (BOOST_RV_REF(shared_lock) that) BOOST_NOEXCEPT
129 {
130 swap((shared_lock&)that);
131 return *this;
132 }
133
operator =(BOOST_RV_REF (unique_lock<mutex_type>)that)134 shared_lock& operator= (BOOST_RV_REF(unique_lock< mutex_type >) that)
135 {
136 shared_lock temp(boost::move(that));
137 swap(temp);
138 return *this;
139 }
140
operator =(BOOST_RV_REF (upgrade_lock<mutex_type>)that)141 shared_lock& operator= (BOOST_RV_REF(upgrade_lock< mutex_type >) that)
142 {
143 shared_lock temp(boost::move(that));
144 swap(temp);
145 return *this;
146 }
147
lock()148 void lock()
149 {
150 if (!m_mutex)
151 BOOST_SYNC_DETAIL_THROW(lock_error, (detail::system_ns::errc::operation_not_permitted)("boost shared_lock has no mutex"));
152
153 if (m_is_locked)
154 BOOST_SYNC_DETAIL_THROW(lock_error, (detail::system_ns::errc::resource_deadlock_would_occur)("boost shared_lock already owns the mutex"));
155
156 m_mutex->lock_shared();
157 m_is_locked = true;
158 }
159
try_lock()160 bool try_lock()
161 {
162 if (!m_mutex)
163 BOOST_SYNC_DETAIL_THROW(lock_error, (detail::system_ns::errc::operation_not_permitted)("boost shared_lock has no mutex"));
164
165 if (m_is_locked)
166 BOOST_SYNC_DETAIL_THROW(lock_error, (detail::system_ns::errc::resource_deadlock_would_occur)("boost shared_lock already owns the mutex"));
167
168 m_is_locked = m_mutex->try_lock_shared();
169
170 return m_is_locked;
171 }
172
173 template< typename Time >
timed_lock(Time const & time)174 typename enable_if_c< detail::time_traits< Time >::is_specialized, bool >::type timed_lock(Time const& time)
175 {
176 if (!m_mutex)
177 BOOST_SYNC_DETAIL_THROW(lock_error, (detail::system_ns::errc::operation_not_permitted)("boost shared_lock has no mutex"));
178
179 if (m_is_locked)
180 BOOST_SYNC_DETAIL_THROW(lock_error, (detail::system_ns::errc::resource_deadlock_would_occur)("boost shared_lock already owns the mutex"));
181
182 m_is_locked = m_mutex->timed_lock_shared(time);
183
184 return m_is_locked;
185 }
186
187 template< typename Duration >
try_lock_for(Duration const & rel_time)188 typename detail::enable_if_tag< Duration, detail::time_duration_tag, bool >::type try_lock_for(Duration const& rel_time)
189 {
190 if (!m_mutex)
191 BOOST_SYNC_DETAIL_THROW(lock_error, (detail::system_ns::errc::operation_not_permitted)("boost shared_lock has no mutex"));
192
193 if (m_is_locked)
194 BOOST_SYNC_DETAIL_THROW(lock_error, (detail::system_ns::errc::resource_deadlock_would_occur)("boost shared_lock already owns the mutex"));
195
196 m_is_locked = m_mutex->try_lock_shared_for(rel_time);
197
198 return m_is_locked;
199 }
200
201 template< typename TimePoint >
try_lock_until(TimePoint const & abs_time)202 typename detail::enable_if_tag< TimePoint, detail::time_point_tag, bool >::type try_lock_until(TimePoint const& abs_time)
203 {
204 if (!m_mutex)
205 BOOST_SYNC_DETAIL_THROW(lock_error, (detail::system_ns::errc::operation_not_permitted)("boost shared_lock has no mutex"));
206
207 if (m_is_locked)
208 BOOST_SYNC_DETAIL_THROW(lock_error, (detail::system_ns::errc::resource_deadlock_would_occur)("boost shared_lock already owns the mutex"));
209
210 m_is_locked = m_mutex->try_lock_shared_until(abs_time);
211
212 return m_is_locked;
213 }
214
unlock()215 void unlock()
216 {
217 if (!m_mutex)
218 BOOST_SYNC_DETAIL_THROW(lock_error, (detail::system_ns::errc::operation_not_permitted)("boost shared_lock has no mutex"));
219
220 if (!m_is_locked)
221 BOOST_SYNC_DETAIL_THROW(lock_error, (detail::system_ns::errc::operation_not_permitted)("boost shared_lock doesn't own the mutex"));
222
223 m_mutex->unlock_shared();
224 m_is_locked = false;
225 }
226
227 BOOST_EXPLICIT_OPERATOR_BOOL()
228
229 bool operator! () const BOOST_NOEXCEPT
230 {
231 return !m_is_locked;
232 }
233
owns_lock() const234 bool owns_lock() const BOOST_NOEXCEPT
235 {
236 return m_is_locked;
237 }
238
mutex() const239 mutex_type* mutex() const BOOST_NOEXCEPT
240 {
241 return m_mutex;
242 }
243
release()244 mutex_type* release() BOOST_NOEXCEPT
245 {
246 mutex_type* const res = m_mutex;
247 m_mutex = NULL;
248 m_is_locked = false;
249 return res;
250 }
251
swap(shared_lock & that)252 void swap(shared_lock& that) BOOST_NOEXCEPT
253 {
254 mutex_type* const p = m_mutex;
255 m_mutex = that.m_mutex;
256 that.m_mutex = p;
257 const bool f = m_is_locked;
258 m_is_locked = that.m_is_locked;
259 that.m_is_locked = f;
260 }
261 };
262
263 template< typename Mutex >
swap(shared_lock<Mutex> & lhs,shared_lock<Mutex> & rhs)264 inline void swap(shared_lock< Mutex >& lhs, shared_lock< Mutex >& rhs) BOOST_NOEXCEPT
265 {
266 lhs.swap(rhs);
267 }
268
269 } // namespace sync
270
271 } // namespace boost
272
273 #include <boost/sync/detail/footer.hpp>
274
275 #endif // BOOST_SYNC_LOCKS_SHARED_LOCK_HPP_INCLUDED_
276