ALib C++ Library
Library Version: 2412 R0
Documentation generated by doxygen
Loading...
Searching...
No Matches
sharedtimedlock.hpp
Go to the documentation of this file.
1//==================================================================================================
2/// \file
3/// This header file is part of module \alib_threads of the \aliblong.
4///
5/// \emoji :copyright: 2013-2024 A-Worx GmbH, Germany.
6/// Published under \ref mainpage_license "Boost Software License".
7//==================================================================================================
8#ifndef HPP_ALIB_THREADS_SHAREDTIMEDLOCK
9#define HPP_ALIB_THREADS_SHAREDTIMEDLOCK 1
10#pragma once
11#if !defined(DOXYGEN)
12# include "alib/alib.hpp"
13#endif
14ALIB_ASSERT_MODULE(THREADS)
15#if ALIB_DEBUG
17#endif
18#if ALIB_DEBUG_CRITICAL_SECTIONS
20#endif
21
22#include "alib/time/ticks.hpp"
23#include <shared_mutex>
24#include <atomic>
25
26namespace alib { namespace threads {
27// =================================================================================================
28/// This class is a simple wrapper around C++ standard library type \c std::shared_timed_mutex.
29/// Thus, it is used to implement <em>mutual exclusive access</em> to resources by protecting
30/// critical code sections from being executed in parallel in concurrent threads, while
31/// allowing typical read-operations to continue to be executed in parallel. <br>
32/// With release-compilations, the only difference to using \c std::shared_timed_mutex directly
33/// is that "spurious wake-ups" are detected and mitigated by this implementation.
34///
35/// When a pair of #Acquire and #Release invocations is performed within the same code block, then
36/// it is recommended to use a stack instantiation of class \alib{lang;Owner} to acquire and release
37/// objects of this class.
38/// Such a use is highly simplified with macros \ref ALIB_LOCK and \ref ALIB_LOCK_WITH. <br>
39/// The same is recommended for paired invocations of #AcquireShared and #ReleaseShared.
40/// Here, class \alib{lang;OwnerShared} is to be used, best using macros \ref ALIB_LOCK_SHARED and
41/// \ref ALIB_LOCK_SHARED_WITH.
42///
43/// This class does not allow nested calls to the method #Acquire - method #Release has to be
44/// invoked (from within the same thread that acquired this mutex), before any other thread can
45/// again gain access. Nested acquisitions constitute undefined behavior.
46///
47/// \par Debug-Features
48/// Public member #Dbg is available with debug-compilations. It offers the following features:
49/// - An assertion is raised when nested use is performed.
50/// - The object stores the actual owning thread and the source code position of the last
51/// acquirement.
52/// Likewise the last shared acquirement's caller information is stored.
53/// - Releasing non-acquired instances, as well as destructing acquired one, raises an assertion.
54/// - Field \alib{threads;DbgLockAsserter;WaitTimeLimit} the raise of \alib warnings in case a
55/// certain wait time is exceeded.
56/// - Field #DbgWarningMaximumShared enables the raise of \alib warnings in the case that
57/// the number of parallel shared acquirements reaches the limit given with this member.
58///
59/// @see
60/// - Chapter \ref alib_threads_locks of the Programmer's Manual of the module \alib_threads_nl.
61/// - Chapter \ref alib_manual_appendix_callerinfo of the General Programmer's Manual.
62// =================================================================================================
66#endif
67{
68 protected:
69 /// The internal object to lock on.
70 std::shared_timed_mutex mutex;
71
72 public:
73 #if ALIB_DEBUG
74 /// The debug tool instance.
76
77 /// Warning-threshold of maximum number of parallel shared acquisitions.<br>
78 /// Defaults to 10.
79 std::atomic<int> DbgWarningMaximumShared =10;
80
81 #if ALIB_DEBUG_CRITICAL_SECTIONS
82 /// Destructor. With debug-compilations, asserts that this lock is not acquired.
84 { Dbg.AssertNotOwned( ALIB_CALLER, ALIB_CALLER, "Destructing acquired lock" ); }
85
86 /// @return \c true if the lock is acquired (in non-shared mode), \c false otherwise.
87 ALIB_API virtual bool DCSIsAcquired() const override;
88
89 /// @return \c true if the lock is shared-acquired (by at least any thread).
90 /// Otherwise, returns \c false.
91 ALIB_API virtual bool DCSIsSharedAcquired() const override;
92 #elif ALIB_DEBUG
94 { Dbg.AssertNotOwned( ALIB_CALLER, ALIB_CALLER, "Destructing acquired lock" ); }
95 #endif
96 #endif
97
98 // ===============================================================================================
99 // ==== Standard Acquire/Release (Writer)
100 // ===============================================================================================
101
102 #if ALIB_DEBUG || DOXYGEN
103 /// Same as #TryAcquireTimed(const Ticks::Duration&, const CallerInfo&)
104 /// but misses the parameter \p{waitTime}. Using this method, the behavior is equivalent to that
105 /// of sibling type \alib{threads;Lock}.
106 ///
107 /// \par Debug Parameter:
108 /// Pass macro \ref ALIB_CALLER_PRUNED with invocations.
111
112 /// Tries to acquire this lock.
113 /// Multiple (nested) successful calls to this method or method #Acquire are not supported and
114 /// lead to undefined behavior.
115 ///
116 /// \par Debug Parameter:
117 /// Pass macro \ref ALIB_CALLER_PRUNED with invocations.
118 /// @return \c true if the lock was not acquired by a different thread and thus, this
119 /// call was successful. \c false otherwise.
121 [[nodiscard]]
123
124 /// A thread which invokes this method gets registered as the current owner of this object,
125 /// until the same thread releases the ownership invoking #Release.
126 /// In the case that this object is already owned by another thread, the invoking thread is
127 /// suspended until ownership can be gained.
128 /// Multiple (nested) calls to this method are not supported and lead to undefined behavior.
129 ///
130 /// @param waitDuration The maximum time-span to wait.
131 /// @param ci Caller information.
132 /// Use macro \ref ALIB_COMMA_CALLER_PRUNED with invocations.
133 /// @return \c true if the lock was acquired, \c false if the \p{waitDuration} expired
134 /// without successful acquisition
136 [[nodiscard]]
137 bool TryAcquireTimed( const Ticks::Duration& waitDuration, const CallerInfo& ci );
138
139 /// Same as overloaded sibling, but expects a C++ standard library duration type
140 /// rather than an \b Ticks::Duration.
141 ///
142 /// @param waitDuration The point in time, when this method stops waiting.
143 /// @param ci Caller information.
144 /// Use macro \ref ALIB_COMMA_CALLER_PRUNED with invocations.
145 /// @return \c true if the lock was acquired, \c false if the \p{pointInTime} was reached
146 /// without successful acquisition.
147 [[nodiscard]]
148 bool TryAcquireTimed( const Ticks::Duration::TDuration& waitDuration, const CallerInfo& ci )
149 { return TryAcquireTimed( Ticks::Duration(waitDuration), ci); }
150
151 /// Same as overloaded sibling, but expects a point in time rather than an \b Ticks::Duration.
152 ///
153 /// @param pointInTime The point in time, when this method stops waiting.
154 /// @param ci Caller information.
155 /// Use macro \ref ALIB_COMMA_CALLER_PRUNED with invocations.
156 /// @return \c true if the lock was acquired, \c false if the \p{pointInTime} was reached
157 /// without successful acquisition.
158 [[nodiscard]]
159 bool TryAcquireTimed( const Ticks& pointInTime, const CallerInfo& ci )
160 { return TryAcquireTimed( pointInTime - Ticks::Now(), ci); }
161
162 /// Same as overloaded sibling, but expects a C++ standard library point in time type
163 /// rather than an \b Ticks::Duration.
164 /// \par Debug Parameter:
165 /// Pass macro \ref ALIB_COMMA_CALLER_PRUNED with invocations.
166 ///
167 /// @param pointInTime The point in time, when this method stops waiting.
168 /// @param ci Caller information.
169 /// Use macro \ref ALIB_COMMA_CALLER_PRUNED with invocations.
170 /// @return \c true if the lock was acquired, \c false if the \p{pointInTime} was reached
171 /// without successful acquisition.
172 [[nodiscard]]
173 bool TryAcquireTimed( const Ticks::TTimePoint& pointInTime, const CallerInfo& ci )
174 { return TryAcquireTimed( Ticks(pointInTime), ci); }
175
176 //==============================================================================================
177 /// Releases ownership of this object.
178 /// If this method is invoked on an object that is not acquired, in debug-compilations an
179 /// assertion is raised. In release compilations, this leads to undefined behavior.
180 /// \par Debug Parameter:
181 /// Pass macro \ref ALIB_CALLER_PRUNED with invocations.
182 //==============================================================================================
185
186 #else // release
187 void Acquire() { mutex.lock(); }
188 [[nodiscard]] bool TryAcquire() { return mutex.try_lock(); }
189 ALIB_API [[nodiscard]] bool TryAcquireTimed( const Ticks::Duration& waitDuration );
190 [[nodiscard]] bool TryAcquireTimed( const Ticks::Duration::TDuration& waitDuration ) { return TryAcquireTimed( Ticks::Duration(waitDuration) ); }
191 [[nodiscard]] bool TryAcquireTimed( const Ticks& pointInTime ) { return TryAcquireTimed( pointInTime - Ticks::Now() ); }
192 [[nodiscard]] bool TryAcquireTimed( const Ticks::TTimePoint& pointInTime ) { return TryAcquireTimed( Ticks(pointInTime) ); }
193 void Release() { mutex.unlock(); }
194
195 #endif
196
197 // ===============================================================================================
198 // ==== Shared Acquire/Release (Reader)
199 // ===============================================================================================
200
201 #if ALIB_DEBUG || DOXYGEN
202 /// Same as #TryAcquireSharedTimed(const Ticks::Duration&, const CallerInfo&)
203 /// but misses the parameter \p{waitTime}.
204 /// Using this method, the behavior is equivalent to that of sibling type
205 /// \alib{threads;SharedLock}.
206 ///
207 /// \par Debug Parameter:
208 /// Pass macro \ref ALIB_CALLER_PRUNED with invocations.
211
212 /// Tries to acquire this lock in shared mode.
213 /// Multiple (nested) calls to this method or method #AcquireShared from within the same thread
214 /// are not supported and lead to undefined behavior.
215 ///
216 /// \par Debug Parameter:
217 /// Pass macro \ref ALIB_CALLER_PRUNED with invocations.
218 /// @return \c true if the lock was not acquired by a different thread and thus, this
219 /// call was successful. \c false otherwise.
221 [[nodiscard]]
223
224 /// Same as method #TryAcquireShared(ALIB_DBG_TAKE_CI), but
225 /// accepts a maximum wait time as first parameter.
226 ///
227 /// @param waitDuration The maximum time-span to wait.
228 /// @param ci Caller information.
229 /// Use macro \ref ALIB_COMMA_CALLER_PRUNED with invocations.
230 /// @return \c true if the lock was acquired, \c false if the \p{waitDuration} expired
231 /// without successful acquisition
233 [[nodiscard]]
234 bool TryAcquireSharedTimed( const Ticks::Duration& waitDuration, const CallerInfo& ci );
235
236 /// Same as overloaded sibling, but expects a C++ standard library duration type
237 /// rather than an \b Ticks::Duration.
238 ///
239 /// @param waitDuration The point in time, when this method stops waiting.
240 /// @param ci Caller information. Available only with debug-builds.
241 /// @return \c true if the lock was acquired, \c false if the \p{pointInTime} was reached
242 /// without successful acquisition.
243 [[nodiscard]]
244 bool TryAcquireSharedTimed(const Ticks::Duration::TDuration& waitDuration, const CallerInfo& ci)
245 { return TryAcquireSharedTimed( Ticks::Duration(waitDuration), ci); }
246
247 /// Same as overloaded sibling, but expects a point in time rather than an \b Ticks::Duration.
248 ///
249 /// @param pointInTime The point in time, when this method stops waiting.
250 /// @param ci Caller information.
251 /// Use macro \ref ALIB_COMMA_CALLER_PRUNED with invocations.
252 /// @return \c true if the lock was acquired, \c false if the \p{pointInTime} was reached
253 /// without successful acquisition.
254 [[nodiscard]]
255 bool TryAcquireSharedTimed( const Ticks& pointInTime, const CallerInfo& ci )
256 { return TryAcquireSharedTimed( pointInTime - Ticks::Now(), ci); }
257
258 /// Same as overloaded sibling, but expects a C++ standard library point in time type
259 /// rather than a \b Ticks::Duration value.
260 ///
261 /// @param pointInTime The point in time, when this method stops waiting.
262 /// @param ci Caller information.
263 /// Use macro \ref ALIB_COMMA_CALLER_PRUNED with invocations.
264 /// @return \c true if the lock was acquired, \c false if the \p{pointInTime} was reached
265 /// without successful acquisition.
266 [[nodiscard]]
267 bool TryAcquireSharedTimed( const Ticks::TTimePoint& pointInTime, const CallerInfo& ci )
268 { return TryAcquireSharedTimed( Ticks(pointInTime), ci); }
269
270 #else // release
271 void AcquireShared() { mutex.lock_shared(); }
272 [[nodiscard]] bool TryAcquireShared() { return mutex.try_lock_shared(); }
273 ALIB_API [[nodiscard]] bool TryAcquireSharedTimed( const Ticks::Duration& waitDuration );
274 [[nodiscard]] bool TryAcquireSharedTimed( const Ticks::Duration::TDuration& waitDuration ) { return TryAcquireSharedTimed( Ticks::Duration(waitDuration) ); }
275 [[nodiscard]] bool TryAcquireSharedTimed( const Ticks& pointInTime ) { return TryAcquireSharedTimed( pointInTime - Ticks::Now() ); }
276 [[nodiscard]] bool TryAcquireSharedTimed( const Ticks::TTimePoint& pointInTime ) { return TryAcquireSharedTimed( Ticks(pointInTime) ); }
277 #endif
278
279 #if ALIB_DEBUG || DOXYGEN
280 /// Releases shared ownership of this object.
281 /// Invoking this method on an object that is not "shared acquired" by this thread constitutes
282 /// undefined behavior.<br>
283 /// In debug-compilations the overall sum (of any thread) of shared acquirements and releases
284 /// is counted, and an assertion is raised if more releases than acquisitions are performed.
285 /// \par Debug Parameter:
286 /// Pass macro \ref ALIB_CALLER_PRUNED with invocations.
289 #else
291 void ReleaseShared() { mutex.unlock_shared(); }
292 #endif
293};
294
295} // namespace alib[::threads]
296
297/// Type alias in namespace \b alib.
299
300} // namespace [alib]
301
302#endif // HPP_ALIB_THREADS_SHAREDTIMEDLOCK
303
virtual ALIB_API bool DCSIsAcquired() const override
Definition locks.cpp:283
ALIB_API bool TryAcquireShared(ALIB_DBG_TAKE_CI)
Definition locks.cpp:939
ALIB_API bool TryAcquireTimed(const Ticks::Duration &waitDuration, const CallerInfo &ci)
Definition locks.cpp:847
ALIB_API void AcquireShared(ALIB_DBG_TAKE_CI)
Definition locks.cpp:899
bool TryAcquireSharedTimed(const Ticks::TTimePoint &pointInTime, const CallerInfo &ci)
virtual ALIB_API bool DCSIsSharedAcquired() const override
Definition locks.cpp:286
DbgSharedLockAsserter Dbg
The debug tool instance.
bool TryAcquireTimed(const Ticks::TTimePoint &pointInTime, const CallerInfo &ci)
~SharedTimedLock() override
Destructor. With debug-compilations, asserts that this lock is not acquired.
ALIB_API bool TryAcquireSharedTimed(const Ticks::Duration &waitDuration, const CallerInfo &ci)
Definition locks.cpp:958
std::shared_timed_mutex mutex
The internal object to lock on.
bool TryAcquireSharedTimed(const Ticks::Duration::TDuration &waitDuration, const CallerInfo &ci)
bool TryAcquireTimed(const Ticks::Duration::TDuration &waitDuration, const CallerInfo &ci)
bool TryAcquireSharedTimed(const Ticks &pointInTime, const CallerInfo &ci)
ALIB_API void ReleaseShared(ALIB_DBG_TAKE_CI)
Definition locks.cpp:985
ALIB_API bool TryAcquire(ALIB_DBG_TAKE_CI)
Definition locks.cpp:834
ALIB_API void Acquire(ALIB_DBG_TAKE_CI)
Definition locks.cpp:801
ALIB_API void Release(ALIB_DBG_TAKE_CI)
Definition locks.cpp:868
std::atomic< int > DbgWarningMaximumShared
bool TryAcquireTimed(const Ticks &pointInTime, const CallerInfo &ci)
typename std::chrono::steady_clock::time_point TTimePoint
#define ALIB_DBG_TAKE_CI
Definition alib.hpp:1176
#define ALIB_ASSERT_MODULE(modulename)
Definition alib.hpp:223
#define ALIB_CALLER
Definition alib.hpp:1164
#define ALIB_FORCE_INLINE
Definition alib.hpp:650
#define ALIB_API
Definition alib.hpp:639
#define ALIB_DEBUG_CRITICAL_SECTIONS
Definition prepro.md:44
Definition alib.cpp:69
time::Ticks Ticks
Type alias in namespace alib.
Definition ticks.hpp:115
lang::CallerInfo CallerInfo
Type alias in namespace alib.
Definition alib.hpp:1143
void AssertNotOwned(const CallerInfo &assertCI, const CallerInfo &ci, const NString &headline)