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