ALib C++ Library
Library Version: 2510 R0
Documentation generated by doxygen
Loading...
Searching...
No Matches
sharedlock.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_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.
16///
17/// When a pair of #Acquire and #Release invocations is performed within the same code block, then
18/// it is recommended to use a stack instantiation of class \alib{lang;Owner} to acquire and release
19/// objects of this class.
20/// Such a use is highly simplified with macros \ref ALIB_LOCK and \ref ALIB_LOCK_WITH.<br>
21/// The same is recommended for paired invocations of #AcquireShared and #ReleaseShared.
22/// Here, class \alib{lang;OwnerShared} is to be used, best using macros \ref ALIB_LOCK_SHARED and
23/// \ref ALIB_LOCK_SHARED_WITH.
24///
25/// This class does not allow nested calls to the method #Acquire - method #Release has to be
26/// invoked (from within the same thread that acquired this mutex), before any other thread can
27/// again gain access. Nested acquisitions constitute undefined behavior.
28///
29/// Typically macros \ref ALIB_LOCK and \ref ALIB_LOCK_WITH should be used to acquire
30/// this lock in non-shared mode and macros ALIB_LOCK_SHARED and \ref ALIB_LOCK_SHARED_WITH
31/// for shared acquisitions.
32///
33/// \par Debug-Features
34/// Public member #Dbg is available with debug-compilations. It offers the following features:
35/// - An assertion is raised when nested use is performed.
36/// - The object stores the actual owning thread and the source code position of the last
37/// acquirement.
38/// Likewise the last shared acquirement's caller information is stored.
39/// - Releasing non-acquired instances, as well as destructing acquired one, raise an assertion.
40/// - Field \alib{threads;DbgLockAsserter;WaitTimeLimit} enables the raise of \alib warnings in case a
41/// certain wait time is exceeded.
42/// Note that instead of wrapping \c std::shared_mutex, with debug-compilations class
43/// \c std::shared_timed_mutex is wrapped.
44/// - Field #DbgWarningMaximumShared enables the raise of \alib warnings in the case that
45/// the number of parallel shared acquirements reaches the limit given with this member.
46///
47/// \par Availability
48/// This type is not available if the compiler-symbol \ref ALIB_SINGLE_THREADED is set.
49///
50/// @see
51/// - Chapter \ref alib_threads_locks of the Programmer's Manual of the module \alib_threads_nl.
52/// - Chapter \ref alib_manual_appendix_callerinfo of the General Programmer's Manual.
53// =================================================================================================
57#endif
58{
59 protected:
60 #if !ALIB_DEBUG && !DOXYGEN
61 std::shared_mutex mutex; // the only member in release compilations
62
63 #else
64 #if DOXYGEN
65 /// The internal object to lock on.
66 /// \note With debug-compilations, this is of type <c>std::timed_mutex</c>.
67 std::shared_mutex mutex;
68 #else
69 std::shared_timed_mutex mutex;
70 #endif
71
72 public:
73 /// The debug tool instance.
75
76 /// Warning-threshold of maximum number of parallel shared acquisitions.<br>
77 /// Defaults to 10.
78 std::atomic<int> DbgWarningMaximumShared =10;
79 #endif
80 public:
81
82 #if ALIB_DEBUG_CRITICAL_SECTIONS
83 /// Destructor. With debug-compilations, asserts that this lock is not acquired.
84 ~SharedLock() override
85 { Dbg.AssertNotOwned( ALIB_CALLER, ALIB_CALLER, "Destructing acquired lock" ); }
86
87 /// @return \c true if the lock is acquired (in non-shared mode), \c false otherwise.
88 ALIB_DLL virtual bool DCSIsAcquired() const override;
89
90 /// @return \c true if the lock is shared-acquired (by at least any thread).
91 /// Otherwise, returns \c false.
92 ALIB_DLL virtual bool DCSIsSharedAcquired() const override;
93 #elif ALIB_DEBUG
95 { Dbg.AssertNotOwned( ALIB_CALLER, ALIB_CALLER, "Destructing acquired lock" ); }
96 #endif
97
98 // ===============================================================================================
99 // ==== Standard Acquire/Release (Writer)
100 // ===============================================================================================
101
102 #if ALIB_DEBUG || DOXYGEN
103 /// Acquires this lock.
104 /// In the case that this object is already owned by another thread, the invoking thread is
105 /// suspended until ownership can be gained.
106 /// Multiple (nested) calls to this method are not supported and lead to undefined behavior.
107 ///
108 /// \par Debug Parameter:
109 /// Pass macro \ref ALIB_CALLER_PRUNED with invocations.
112
113 /// Tries to acquire this lock.
114 /// Multiple (nested) successful calls to this method or method #Acquire are not supported and
115 /// lead to undefined behavior.
116 ///
117 /// \par Debug Parameter:
118 /// Pass macro \ref ALIB_CALLER_PRUNED with invocations.
119 /// @return \c true if the lock was not acquired by a different thread and thus, this
120 /// call was successful. \c false otherwise.
122 [[nodiscard]]
124
125 /// Releases ownership of this object.
126 /// If this method is invoked on an object that is not acquired, in debug-compilations an
127 /// assertion is raised. In release compilations, this leads to undefined behavior.
128 /// \par Debug Parameter:
129 /// Pass macro \ref ALIB_COMMA_CALLER_PRUNED with invocations.
132
133 #else
134 void Acquire() { mutex.lock(); }
135 [[nodiscard]] bool TryAcquire() { return mutex.try_lock(); }
136 void Release() { mutex.unlock(); }
137
138 #endif
139
140
141 // ===============================================================================================
142 // ==== Shared Acquire/Release (Reader)
143 // ===============================================================================================
144 #if ALIB_DEBUG || DOXYGEN
145 /// Acquires this lock in shared mode.
146 /// In the case that this object is already owned (not shared) by another thread, the invoking
147 /// thread is suspended until ownership can be gained.
148 /// Multiple (nested) calls to this method are not supported and lead to undefined behavior.
149 ///
150 /// \par Debug Parameter:
151 /// Pass macro \ref ALIB_CALLER_PRUNED with invocations.
153 void
155
156 /// Tries to acquire this lock.
157 /// Multiple (nested) calls to this method or method #AcquireShared from within the same thread
158 /// are not supported and lead to undefined behavior.
159 ///
160 /// \par Debug Parameter:
161 /// Pass macro \ref ALIB_CALLER_PRUNED with invocations.
162 /// @return \c true if the lock was not acquired by a different thread and thus, this
163 /// call was successful. \c false otherwise.
165 [[nodiscard]]
167
168 /// Releases shared ownership of this object.
169 /// Invoking this method on an object that is not "shared acquired" by this thread constitutes
170 /// undefined behavior.<br>
171 /// In debug-compilations the overall sum (of any thread) of shared acquirements and releases
172 /// is counted, and an \ref alib_mod_assert "error is raised" if more releases than
173 /// acquisitions are performed.
174 /// \par Debug Parameter:
175 /// Pass macro \ref ALIB_CALLER_PRUNED with invocations.
178 #else
179 void AcquireShared() { mutex.lock_shared(); }
180 [[nodiscard]] bool TryAcquireShared() { return mutex.try_lock_shared(); }
181 void ReleaseShared() { mutex.unlock_shared(); }
182 #endif
183
184};
185
186
187} // namespace alib[threads]
188
189/// Type alias in namespace \b alib.
191
192} // namespace [alib]
193#endif // !ALIB_SINGLE_THREADED
194
ALIB_DLL bool TryAcquire(ALIB_DBG_TAKE_CI)
Definition locks.cpp:455
std::atomic< int > DbgWarningMaximumShared
ALIB_DLL void Release(ALIB_DBG_TAKE_CI)
Definition locks.cpp:468
std::shared_mutex mutex
DbgSharedLockAsserter Dbg
The debug tool instance.
ALIB_DLL void ReleaseShared(ALIB_DBG_TAKE_CI)
Definition locks.cpp:535
virtual ALIB_DLL bool DCSIsSharedAcquired() const override
Definition locks.cpp:768
ALIB_DLL void AcquireShared(ALIB_DBG_TAKE_CI)
Definition locks.cpp:478
~SharedLock() override
Destructor. With debug-compilations, asserts that this lock is not acquired.
ALIB_DLL bool TryAcquireShared(ALIB_DBG_TAKE_CI)
Definition locks.cpp:517
virtual ALIB_DLL bool DCSIsAcquired() const override
Definition locks.cpp:767
ALIB_DLL void Acquire(ALIB_DBG_TAKE_CI)
Definition locks.cpp:420
#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::SharedLock SharedLock
Type alias in namespace alib.
void AssertNotOwned(const CallerInfo &assertCI, const CallerInfo &ci, const char *headline)