ALib C++ Library
Library Version: 2412 R0
Documentation generated by doxygen
Loading...
Searching...
No Matches
dbglockasserter.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_DBGLOCKS
9#define HPP_ALIB_THREADS_DBGLOCKS 1
10#pragma once
11#include "thread.hpp"
12
13#if ALIB_DEBUG
14#include <atomic>
16#include "alib/time/ticks.hpp"
17
18namespace alib::threads {
19
20class Thread;
21
22//==================================================================================================
23/// This type is used for debugging and asserting \alib lock (mutex) types.
24/// With debug compilations the non-shared lock types hold one member of this struct, which
25/// aggregates all debug information.
26//==================================================================================================
28{
29 /// The name of this Lock.
30 /// Set to <em> "<unnamed>"</em> by default.
31 /// Used for debug-output.
32 /// For automatic pruning of changes to this name, macro \ref ALIB_DBG should be used.
33 const char* Name ="<unnamed>";
34 CallerInfo AcqCI ; ///< Source location of the most recent acquirement.
35 CallerInfo RelCI ; ///< Source location of the most recent release.
36 int16_t CntAcquirements= 0; ///< The number of nested acquirements.
37
38#if ALIB_CAMP
39 /// The format string used to write exceptions to the console.
40 /// This string can be changed if the source information is not "clickable" in a user's
41 /// development environment.<br>
42 ///
43 /// The default string is optimized for
44 /// \https{JetBrains CLion,www.jetbrains.com/clion} and is defined as:
45 /** \verbatim
46Multi-Threadding {} in Lock {!Q}
47 Message: {}
48 In (Member-)Function: {:ya}
49 Is Owned: {7}
50
51 Called By: {4:ya}
52 At: {4:sf:sl}
53 Thread: {4:ta}
54
55 Latest Acquisition By: {5:ya}
56 At: {5:sf:sl}
57 Thread: {5:ta}
58 Latest Release By: {6:ya}
59 At: {6:sf:sl}
60 Thread: {6:ta}
61 \endverbatim
62 <p>
63 The placeholder fields that this format string refers to are set as follows:
64 - \c 0: String "Assertion" or "Warning"
65 - \c 1: Debug-name of the lock.
66 - \c 2: Headline.
67 - \c 3: \b %CallerInfo of assertion.
68 - \c 4: \b %CallerInfo of caller.
69 - \c 5: \b %CallerInfo of latest acquisition.
70 - \c 6: \b %CallerInfo of latest release.
71 - \c 7: Acquirement information string
72
73 The format specification of the type \c CallerInfo is defined with class
74 \alib{lang::format;FMTCallerInfo}.
75 \par Availability:
76 This field is only available with the inclusion of \alib_basecamp in the \alibdist.<br> */
79#endif
80
81
82 /// This is a threshold that causes non-timed Acquire() methods to raise a \alib warning in
83 /// debug-builds in case a thread is blocked longer than the given duration.
84 ///
85 /// To disable warnings in cases that high block times are suitable, set this value to \c 0.
86 /// The default value is two seconds.
87 Ticks::Duration WaitTimeLimit = Ticks::Duration::FromAbsoluteSeconds(2);
88
89 /// Limit of recursions. If the limit is reached or a multiple of it, a warning is passed
90 /// to \alib{lang;ReportWriter}.
91 /// Defaults is \c 10. To disable, set to \c 0.<p>
92 /// Available only in debug versions of \alib.
94
95 /// Destructor.
96 virtual ~DbgLockAsserter() {}
97
98 /// Returns a pointer the owning thread.<p>
99 /// Available only in debug-builds.
100 /// @return Pointer to the owning thread, or \c nullptr if not owned.
102 Thread* GetOwner() const;
103
104 /// Returns \c true if the current owner is the current thread.<p>
105 /// Available only in debug-builds.
106 /// @return \c true, if the lock is owned by this thread, \c false if it is owned by
107 /// another thread or not owned.
109 { return CntAcquirements > 0 && AcqCI.ThreadID == std::this_thread::get_id(); }
110
111 /// Returns \c true if this is a non-recursive lock or a recursive instance which is acquired
112 /// exactly once.<br>
113 /// Available only in debug-builds.
114 ///
115 /// \note
116 /// This method is not (and cannot) be synchronized. Consequently, a reliable result
117 /// is only guaranteed in case #IsOwnedByCurrentThread returns \c true before this method
118 /// is invoked.
119 ///
120 /// @return \c true if the next release will free this lock, \c false otherwise.
121 bool WillRelease() const noexcept { return CntAcquirements == 1; }
122
123 /// Writes assertion info and calls \ref ALIB_ASSERT, respectively \ref ALIB_WARNING.
124 /// @see
125 /// Field #ASSERTION_FORMAT which allows changing the output format to achieve 'clickable'
126 /// assertion messages.
127 /// @param type 0= assertion, 1= warning.
128 /// @param assertCI Location where the assertion is placed.
129 /// @param ci Location of the call to the method that asserted.
130 /// @param headline The message.
132 virtual
133 void DoAssert (int type, const CallerInfo& assertCI, const CallerInfo& ci,
134 const NString& headline );
135
136 /// Asserts that #CntAcquirements is not \c 0
137 /// @param assertCI Location where the assertion is placed.
138 /// @param ci Location of the call to the method that asserted.
139 /// @param headline The message.
140 void AssertOwned (const CallerInfo& assertCI, const CallerInfo& ci, const NString& headline )
141 {
142 if( CntAcquirements == 0 )
143 DoAssert( 0, assertCI, ci, headline );
144 }
145
146 /// Asserts that #CntAcquirements is \c 0
147 /// @param assertCI Location where the assertion is placed.
148 /// @param ci Location of the call to the method that asserted.
149 /// @param headline The message.
150 void AssertNotOwned (const CallerInfo& assertCI, const CallerInfo& ci, const NString& headline )
151 {
152 if( CntAcquirements > 0 )
153 DoAssert( 0, assertCI, ci, headline );
154 }
155
156 /// Asserts that either #CntAcquirements is \c 0 or the lock is owned by calling thread.
157 /// @param assertCI Location where the assertion is placed.
158 /// @param ci Location of the call to the method that asserted.
159 /// @param headline The message.
160 void AssertNotOwnedOrMe (const CallerInfo& assertCI, const CallerInfo& ci, const NString& headline )
161 {
162 if( CntAcquirements > 0 && ci.ThreadID != AcqCI.ThreadID )
163 DoAssert( 0, assertCI, ci, headline );
164 }
165
166 /// Asserts that this lock is owned by the thread in \p{ci}.
167 /// @param assertCI Location where the assertion is placed.
168 /// @param ci Location of the call to the method that asserted.
169 /// @param headline The message.
170 void AssertOwning (const CallerInfo& assertCI, const CallerInfo& ci, const NString& headline )
171 {
172 if( CntAcquirements == 0 || ci.ThreadID != AcqCI.ThreadID )
173 DoAssert( 0, assertCI, ci, headline);
174 }
175
176 /// Asserts that this lock is not owned by the thread in \p{ci}.
177 /// @param assertCI Location where the assertion is placed.
178 /// @param ci Location of the call to the method that asserted.
179 /// @param headline The message.
180 void AssertNotOwning(const CallerInfo& assertCI, const CallerInfo& ci, const NString& headline )
181 {
182 if( CntAcquirements > 0 && ci.ThreadID == AcqCI.ThreadID )
183 DoAssert( 0, assertCI, ci, headline);
184 }
185}; // struct DbgLockAsserter
186
187//==================================================================================================
188/// This type is used for debugging and asserting \alib lock (mutex) types.
189/// With debug compilations the shared lock types hold one member of this struct, which
190/// aggregates all debug information.
191//==================================================================================================
193{
194 CallerInfo SAcqCI; ///< Source location of the most recent shared acquirement.
195 CallerInfo SRelCI; ///< Source location of the most recent shared release.
196 std::atomic<int> CntSharedAcquirements{0}; ///< The number of shared acquirements.
197
198#if ALIB_CAMP
199 /// The format string used to write exceptions to the console.
200 /// This string can be changed if the source information is not "clickable" in a user's
201 /// development environment.<br>
202 ///
203 /// The default string is optimized for
204 /// \https{JetBrains CLion,www.jetbrains.com/clion} and is defined as:
205 /** \verbatim
206Multi-Threadding {} in Lock {!Q}
207 Message: {}
208 In (Member-)Function: {:ya}
209 Is Owned: {7}
210 Is Shared Owned: {10}
211 Called By: {4:ya}
212 At: {4:sf:sl}
213 Thread: {4:ta}
214 Latest Acquisition By: {5:ya}
215 At: {5:sf:sl}
216 Thread: {5:ta}
217 Latest Release By: {6:ya}
218 At: {6:sf:sl}
219 Thread: {6:ta}
220 Latest Shared Acquisition By: {8:ya}
221 At: {8:sf:sl}
222 Thread: {8:ta}
223 Latest SharedRelease By: {9:ya}
224 At: {9:sf:sl}
225 Thread: {9:ta}
226 \endverbatim
227 <p>
228 The placeholder fields that this format string refers to are set as follows:
229
230 - \c 0: String "Assertion" or "Warning"
231 - \c 1: Debug-name of the lock.
232 - \c 2: Headline.
233 - \c 3: \b %CallerInfo of assertion.
234 - \c 4: \b %CallerInfo of caller.
235 - \c 5: \b %CallerInfo of latest acquisition.
236 - \c 6: \b %CallerInfo of latest release.
237 - \c 7: Acquirement information string
238 - \c 8: \b %CallerInfo of latest shared acquisition.
239 - \c 9: \b %CallerInfo of latest shared release.
240 - \c 10: Shared acquirement information string.
241
242 The format specification of the type \c CallerInfo is defined with class
243 \alib{lang::format;FMTCallerInfo}.
244 \par Availability:
245 This field is only available with the inclusion of \alib_basecamp in the \alibdist.<br> */
248#endif
249
250
251 /// Destructor.
252 virtual ~DbgSharedLockAsserter() override {}
253
254 /// Writes assertion info and calls \ref ALIB_ASSERT, respectively \ref ALIB_WARNING.
255 /// @see
256 /// Field #ASSERTION_FORMAT which allows changing the output format to achieve 'clickable'
257 /// assertion messages.
258 /// @param type 0= assertion, 1= warning.
259 /// @param assertCI Location where the assertion is placed.
260 /// @param ci Location of the call to the method that asserted.
261 /// @param headline The message.
263 void DoAssert (int type, const CallerInfo& assertCI, const CallerInfo& ci,
264 const NString& headline ) override;
265
266 /// Returns \c true if currently a reader is registered. This method is used to
267 /// create assertions. Of-course, to detect assertions, it would be more efficient to check
268 /// if shared ownership is with the current thread, but a check on this would cost
269 /// a lot of overhead to realize. This way, at least assertions can be raised when no other
270 /// thread acquired this lock in shared mode.<p>
271 /// Available only in debug-builds.
272 /// @return \c true, if the lock is owned by this thread, \c false if it is owned by
273 /// another thread or not owned.
274 bool IsSharedOwnedByAnyThread() const{ return CntSharedAcquirements.load() > 0; }
275
276 /// Asserts that #CntAcquirements is \c 0
277 /// @param assertCI Location where the assertion is placed.
278 /// @param ci Location of the call to the method that asserted.
279 /// @param headline The message.
280 void AssertNotOwned (const CallerInfo& assertCI, const CallerInfo& ci, const NString& headline )
281 {
282 if( CntAcquirements > 0 || CntSharedAcquirements.load() > 0 )
283 DoAssert( 0, assertCI, ci, headline );
284 }
285
286
287}; // struct DbgSharedLockAsserter
288
289} // namespace [alib::threads]
290
291
292#endif // ALIB_DEBUG
293#endif // HPP_ALIB_THREADS_DBGLOCKS
294
#define ALIB_API
Definition alib.hpp:639
threads::Thread Thread
Type alias in namespace alib.
Definition thread.hpp:379
std::thread::id ThreadID
The ID of the calling thread.
Definition alib.hpp:1136
ALIB_API Thread * GetOwner() const
Definition locks.cpp:43
virtual ~DbgLockAsserter()
Destructor.
int16_t CntAcquirements
The number of nested acquirements.
void AssertNotOwned(const CallerInfo &assertCI, const CallerInfo &ci, const NString &headline)
void AssertNotOwning(const CallerInfo &assertCI, const CallerInfo &ci, const NString &headline)
CallerInfo AcqCI
Source location of the most recent acquirement.
void AssertNotOwnedOrMe(const CallerInfo &assertCI, const CallerInfo &ci, const NString &headline)
CallerInfo RelCI
Source location of the most recent release.
void AssertOwning(const CallerInfo &assertCI, const CallerInfo &ci, const NString &headline)
virtual ALIB_API void DoAssert(int type, const CallerInfo &assertCI, const CallerInfo &ci, const NString &headline)
Definition locks.cpp:97
static ALIB_API NString ASSERTION_FORMAT
bool WillRelease() const noexcept
void AssertOwned(const CallerInfo &assertCI, const CallerInfo &ci, const NString &headline)
void AssertNotOwned(const CallerInfo &assertCI, const CallerInfo &ci, const NString &headline)
std::atomic< int > CntSharedAcquirements
The number of shared acquirements.
CallerInfo SAcqCI
Source location of the most recent shared acquirement.
virtual ~DbgSharedLockAsserter() override
Destructor.
ALIB_API void DoAssert(int type, const CallerInfo &assertCI, const CallerInfo &ci, const NString &headline) override
Definition locks.cpp:142
CallerInfo SRelCI
Source location of the most recent shared release.
static ALIB_API NString ASSERTION_FORMAT_SHARED