ALib C++ Library
Library Version: 2510 R0
Documentation generated by doxygen
Loading...
Searching...
No Matches
recursivelock.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_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.
15///
16/// When a pair of #AcquireRecursive and #ReleaseRecursive invocations is performed within the same
17/// code block, then it is recommended to use a stack instantiation of class
18/// \alib{lang;OwnerRecursive} to acquire and release objects of this class.
19/// Such a use is highly simplified with macros \ref ALIB_LOCK_RECURSIVE and
20/// \ref ALIB_LOCK_RECURSIVE_WITH.
21///
22/// Nested acquisitions are supported with this type.
23/// An instance of this class is released when an equal number of invocations to #AcquireRecursive
24/// and #ReleaseRecursive have been performed.<br>
25/// This class has slightly reduced performance in comparison to non-recursive type
26/// \alib{threads;Lock}. Not only for this reason, non-nested locking is the preferred technique.
27/// But there are situations where nested locks are just unavoidable.
28///
29/// \par Debug-Features
30/// Public member #Dbg is available with debug-compilations. It offers the following features:
31/// - The object stores the actual owning thread and the source code position of the last
32/// acquirement.
33/// - Releasing non-acquired instances, as well as destructing acquired one, raise an assertion.
34/// - A warning threshold for the number of nested acquisitions can be defined with public member
35/// \alib{threads;DbgLockAsserter::RecursionLimit}.
36/// - Field \alib{threads;DbgLockAsserter;WaitTimeLimit} enables the raise of \alib warnings in case a
37/// certain wait time is exceeded.
38/// Note that instead of wrapping \c std::recursive_mutex, with debug-compilations class
39/// \c std::recursive_timed_mutex is wrapped.
40///
41/// \par Availability
42/// This type is not available if the compiler-symbol \ref ALIB_SINGLE_THREADED is set.
43///
44/// @see
45/// - Chapter \ref alib_threads_locks of the Programmer's Manual of the module \alib_threads_nl.
46/// - Chapter \ref alib_manual_appendix_callerinfo of the General Programmer's Manual.
47// =================================================================================================
51#endif
52{
53 protected:
54 #if !ALIB_DEBUG && !DOXYGEN
55 std::recursive_mutex mutex; // the only member in release compilations
56
57 #else
58 #if DOXYGEN
59 /// The internal object to lock on.
60 /// \note With debug-compilations, this is of type <c>std::recursive_timed_mutex</c>.
61 std::recursive_mutex mutex;
62 #else
63 std::recursive_timed_mutex mutex;
64 #endif
65
66 public:
67 /// The debug tool instance.
69 #endif
70
71
72 #if ALIB_DEBUG_CRITICAL_SECTIONS
73 /// Destructor. With debug-compilations, asserts that this lock is not acquired.
74 ~RecursiveLock() override
75 { Dbg.AssertNotOwned( ALIB_CALLER, ALIB_CALLER, "Destructing acquired lock" ); }
76
77 /// @return \c true if the lock is acquired (in non-shared mode), \c false otherwise.
78 ALIB_DLL virtual bool DCSIsAcquired() const override;
79
80 /// @return \c true if the lock is shared-acquired (by at least any thread).
81 /// Otherwise, returns \c false.
82 ALIB_DLL virtual bool DCSIsSharedAcquired() const override;
83 #elif ALIB_DEBUG
85 { Dbg.AssertNotOwned( ALIB_CALLER, ALIB_CALLER, "Destructing acquired lock" ); }
86 #endif
87
88 // ###############################################################################################
89 // Interface
90 // ###############################################################################################
91 public:
92
93 #if ALIB_DEBUG || DOXYGEN
94 //==============================================================================================
95 /// Thread which invokes this method gets registered as the current owner of this object,
96 /// until the same thread releases the ownership invoking #ReleaseRecursive.
97 /// In the case that this object is already owned by another thread, the invoking thread is
98 /// suspended until ownership can be gained.
99 /// Multiple (nested) calls to this method are counted and the object is only released when
100 /// the same number of Release() calls have been made.
101 ///
102 /// \par Debug Parameter:
103 /// Pass macro \ref ALIB_CALLER_PRUNED with invocations.
104 //==============================================================================================
107
108 /// Tries to acquire this lock.
109 /// Successful calls to this method are counted, as if #AcquireRecursive was called and an
110 /// according invocation of #ReleaseRecursive has to be performed.
111 ///
112 /// \par Debug Parameter:
113 /// Pass macro \ref ALIB_CALLER_PRUNED with invocations.
114 ///
115 /// @return \c true if the lock was not acquired by a different thread and thus, this
116 /// call was successful. \c false otherwise.
118 [[nodiscard]]
120 #else
121 void AcquireRecursive() { mutex.lock(); }
122 [[nodiscard]] bool TryAcquire() { return mutex.try_lock(); }
123 #endif
124
125 #if ALIB_DEBUG || DOXYGEN
126 /// Releases ownership of this object. If #AcquireRecursive was called multiple times before,
127 /// the same number of calls to this method has to be performed to release ownership.
128 /// \par Debug Parameter:
129 /// Pass macro \ref ALIB_CALLER_PRUNED with invocations.
132 #else
133 void ReleaseRecursive() { mutex.unlock(); }
134 #endif
135};
136
137
138} // namespace alib[threads]
139
140/// Type alias in namespace \b alib.
142
143} // namespace [alib]
144#endif // !ALIB_SINGLE_THREADED
145
146
virtual ALIB_DLL bool DCSIsAcquired() const override
Definition locks.cpp:763
virtual ALIB_DLL bool DCSIsSharedAcquired() const override
Definition locks.cpp:764
ALIB_DLL void AcquireRecursive(ALIB_DBG_TAKE_CI)
Definition locks.cpp:211
std::recursive_mutex mutex
ALIB_DLL void ReleaseRecursive(ALIB_DBG_TAKE_CI)
Definition locks.cpp:280
ALIB_DLL bool TryAcquire(ALIB_DBG_TAKE_CI)
Definition locks.cpp:256
DbgLockAsserter Dbg
The debug tool instance.
~RecursiveLock() override
Destructor. With debug-compilations, asserts that this lock is not acquired.
#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::RecursiveLock RecursiveLock
Type alias in namespace alib.
void AssertNotOwned(const CallerInfo &assertCI, const CallerInfo &ci, const char *headline)