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