ALib C++ Library
Library Version: 2510 R0
Documentation generated by doxygen
Loading...
Searching...
No Matches
recursivetimedlock.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::recursive_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.<br>
15/// With release-compilations, the only difference to using \c std::recursive_timed_mutex directly
16/// is that "spurious wake-ups" are detected and mitigated by this implementation.
17///
18/// code block, then it is recommended to use a stack instantiation of class
19/// \alib{lang;OwnerRecursive} to acquire and release objects of this class.
20/// Such a use is highly simplified with macros \ref ALIB_LOCK_RECURSIVE and
21/// \ref ALIB_LOCK_RECURSIVE_WITH.
22///
23/// Nested acquisitions are supported with this type.
24/// An instance of this class is released when an equal number of invocations to #AcquireRecursive
25/// and #ReleaseRecursive have been performed.<br>
26/// This class has slightly reduced performance in comparison to non-recursive type
27/// \alib{threads;Lock}. Not only for this reason, non-nested locking is the preferred technique.
28/// But there are situations where nested locks are just unavoidable.
29///
30/// \par Debug-Features
31/// Public member #Dbg is available with debug-compilations. It offers the following features:
32/// - The object stores the actual owning thread and the source code position of the last
33/// acquirement.
34/// - Releasing non-acquired instances, as well as destructing acquired one, raise an assertion.
35/// - A warning threshold for the number of nested acquisitions can be defined with public member
36/// \alib{threads;DbgLockAsserter::RecursionLimit}.
37/// - Field \alib{threads;DbgLockAsserter;WaitTimeLimit} enables the raise of \alib warnings in case a
38/// certain wait time is exceeded.
39///
40/// \par Availability
41/// This type is not available if the compiler-symbol \ref ALIB_SINGLE_THREADED is set.
42///
43/// @see
44/// - Chapter \ref alib_threads_locks of the Programmer's Manual of the module \alib_threads_nl.
45/// - Chapter \ref alib_manual_appendix_callerinfo of the General Programmer's Manual.
46// =================================================================================================
50#endif
51{
52 protected:
53 /// The internal object to lock on.
54 std::recursive_timed_mutex mutex; // the only member in release compilations
55
56 public:
57 #if ALIB_DEBUG
58 /// The debug tool instance.
60 #endif
61
62 #if ALIB_DEBUG_CRITICAL_SECTIONS
63 /// Destructor. With debug-compilations, asserts that this lock is not acquired.
65 { Dbg.AssertNotOwned( ALIB_CALLER, ALIB_CALLER, "Destructing acquired lock" ); }
66
67 /// @return \c true if the lock is acquired (in non-shared mode), \c false otherwise.
68 ALIB_DLL virtual bool DCSIsAcquired() const override;
69
70 /// @return \c true if the lock is shared-acquired (by at least any thread).
71 /// Otherwise, returns \c false.
72 ALIB_DLL virtual bool DCSIsSharedAcquired() const override;
73 #elif ALIB_DEBUG
75 { Dbg.AssertNotOwned( ALIB_CALLER, ALIB_CALLER, "Destructing acquired lock" ); }
76 #endif
77
78 // ###############################################################################################
79 // Interface
80 // ###############################################################################################
81 public:
82
83 #if ALIB_DEBUG || DOXYGEN
84 //==============================================================================================
85 /// Thread which invokes this method gets registered as the current owner of this object,
86 /// until the same thread releases the ownership invoking #ReleaseRecursive.
87 /// In the case that this object is already owned by another thread, the invoking thread is
88 /// suspended until ownership can be gained.
89 /// Multiple (nested) calls to this method are counted and the object is only released when
90 /// the same number of Release() calls have been made.
91 ///
92 /// \par Debug Parameter:
93 /// Pass macro \ref ALIB_CALLER_PRUNED with invocations.
94 //==============================================================================================
97
98 /// Tries to acquire this lock.
99 /// Successful calls to this method are counted, as if #AcquireRecursive was called and an
100 /// according invocation of #ReleaseRecursive has to be performed.
101 ///
102 /// \par Debug Parameter:
103 /// Pass macro \ref ALIB_CALLER_PRUNED with invocations.
104 ///
105 /// @return \c true if the lock was not acquired by a different thread and thus, this
106 /// call was successful. \c false otherwise.
108 [[nodiscard]]
110
111 /// A thread which invokes this method gets registered as the current owner of this object,
112 /// until the same thread releases the ownership invoking #ReleaseRecursive.
113 /// In the case that this object is already owned by another thread, the invoking thread is
114 /// suspended until ownership can be gained.<br>
115 /// Successful calls to this method are counted, as if #AcquireRecursive was called and an
116 /// according invocation of #ReleaseRecursive has to be performed.
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 /// @param pointInTime The point in time, when this method stops waiting.
141 /// @param ci Caller information.
142 /// Use macro \ref ALIB_COMMA_CALLER_PRUNED with invocations.
143 /// @return \c true if the lock was acquired, \c false if the \p{pointInTime} was reached
144 /// without successful acquisition.
145 [[nodiscard]]
146 bool TryAcquireTimed( const Ticks& pointInTime, const CallerInfo& ci )
147 { return TryAcquireTimed( pointInTime - Ticks::Now(), ci); }
148
149 /// Same as overloaded sibling, but expects a C++ standard library point in time type
150 /// rather than an \b Ticks::Duration.
151 ///
152 /// @param pointInTime The point in time, when this method stops waiting.
153 /// @param ci Caller information.
154 /// Use macro \ref ALIB_COMMA_CALLER_PRUNED with invocations.
155 /// @return \c true if the lock was acquired, \c false if the \p{pointInTime} was reached
156 /// without successful acquisition.
157 [[nodiscard]]
158 bool TryAcquireTimed( const Ticks::TTimePoint& pointInTime, const CallerInfo& ci )
159 { return TryAcquireTimed( Ticks(pointInTime), ci); }
160
161 #else
162 void AcquireRecursive() { mutex.lock(); }
163 [[nodiscard]] bool TryAcquire() { return mutex.try_lock(); }
164 ALIB_DLL [[nodiscard]] bool TryAcquireTimed( const Ticks::Duration& waitDuration );
165 [[nodiscard]] bool TryAcquireTimed( const Ticks::Duration::TDuration& waitDuration ) { return TryAcquireTimed( Ticks::Duration(waitDuration) ); }
166 [[nodiscard]] bool TryAcquireTimed( const Ticks& pointInTime ) { return TryAcquireTimed( pointInTime - Ticks::Now() ); }
167 [[nodiscard]] bool TryAcquireTimed( const Ticks::TTimePoint& pointInTime ) { return TryAcquireTimed( Ticks(pointInTime) ); }
168 #endif
169
170 #if ALIB_DEBUG || DOXYGEN
171 /// Releases ownership of this object. If #AcquireRecursive was called multiple times before,
172 /// the same number of calls to this method has to be performed to release ownership.
173 /// \par Debug Parameter:
174 /// Pass macro \ref ALIB_CALLER_PRUNED with invocations.
177 #else
178 void ReleaseRecursive() { mutex.unlock(); }
179 #endif
180};
181
182
183} // namespace alib[threads]
184
185/// Type alias in namespace \b alib.
187
188} // namespace [alib]
189#endif // !ALIB_SINGLE_THREADED
190
191
ALIB_DLL void ReleaseRecursive(ALIB_DBG_TAKE_CI)
Definition locks.cpp:408
DbgLockAsserter Dbg
The debug tool instance.
virtual ALIB_DLL bool DCSIsAcquired() const override
Definition locks.cpp:765
~RecursiveTimedLock() override
Destructor. With debug-compilations, asserts that this lock is not acquired.
std::recursive_timed_mutex mutex
The internal object to lock on.
virtual ALIB_DLL bool DCSIsSharedAcquired() const override
Definition locks.cpp:766
ALIB_DLL bool TryAcquireTimed(const Ticks::Duration &waitDuration, const CallerInfo &ci)
Definition locks.cpp:376
ALIB_DLL void AcquireRecursive(ALIB_DBG_TAKE_CI)
Definition locks.cpp:306
ALIB_DLL bool TryAcquire(ALIB_DBG_TAKE_CI)
Definition locks.cpp:352
bool TryAcquireTimed(const Ticks::TTimePoint &pointInTime, const CallerInfo &ci)
bool TryAcquireTimed(const Ticks &pointInTime, const CallerInfo &ci)
bool TryAcquireTimed(const Ticks::Duration::TDuration &waitDuration, const CallerInfo &ci)
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
lang::CallerInfo CallerInfo
Type alias in namespace alib.
time::Ticks Ticks
Type alias in namespace alib.
Definition ticks.inl:109
threads::RecursiveTimedLock RecursiveTimedLock
Type alias in namespace alib.
void AssertNotOwned(const CallerInfo &assertCI, const CallerInfo &ci, const char *headline)