ALib C++ Library
Library Version: 2412 R0
Documentation generated by doxygen
Loading...
Searching...
No Matches
recursivetimedlock.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_RECURSIVETIMEDLOCK
9#define HPP_ALIB_THREADS_RECURSIVETIMEDLOCK 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 "alib/time/ticks.hpp"
23#include <mutex>
24
25namespace alib { namespace threads {
26
27// forwards
28class Thread;
29
30// =================================================================================================
31/// This class is a simple wrapper around C++ standard library type \c std::recursive_timed_mutex.
32/// Thus, it is used to implement <em>mutual exclusive access</em> to resources by protecting
33/// critical code sections from being executed in parallel in concurrent threads.<br>
34/// With release-compilations, the only difference to using \c std::recursive_timed_mutex directly
35/// is that "spurious wake-ups" are detected and mitigated by this implementation.
36///
37/// code block, then it is recommended to use a stack instantiation of class
38/// \alib{lang;OwnerRecursive} to acquire and release objects of this class.
39/// Such a use is highly simplified with macros \ref ALIB_LOCK_RECURSIVE and
40/// \ref ALIB_LOCK_RECURSIVE_WITH.
41///
42/// Nested acquisitions are supported with this type.
43/// An instance of this class is released when an equal number of invocations to #AcquireRecursive
44/// and #ReleaseRecursive have been performed.<br>
45/// This class has slightly reduced performance in comparison to non-recursive type
46/// \alib{threads;Lock}. Not only for this reason, non-nested locking is the preferred technique.
47/// But there are situations where nested locks are just unavoidable.
48///
49/// \par Debug-Features
50/// Public member #Dbg is available with debug-compilations. It offers the following features:
51/// - The object stores the actual owning thread and the source code position of the last
52/// acquirement.
53/// - Releasing non-acquired instances, as well as destructing acquired one, raise an assertion.
54/// - A warning threshold for the number of nested acquisitions can be defined with public member
55/// \alib{threads;DbgLockAsserter::RecursionLimit}.
56/// - Field \alib{threads;DbgLockAsserter;WaitTimeLimit} enables the raise of \alib warnings in case a
57/// certain wait time is exceeded.
58///
59/// @see
60/// - Chapter \ref alib_threads_locks of the Programmer's Manual of the module \alib_threads_nl.
61/// - Chapter \ref alib_manual_appendix_callerinfo of the General Programmer's Manual.
62// =================================================================================================
66#endif
67{
68 protected:
69 /// The internal object to lock on.
70 std::recursive_timed_mutex mutex; // the only member in release compilations
71
72 public:
73 #if ALIB_DEBUG
74 /// The debug tool instance.
76 #endif
77
78 #if ALIB_DEBUG_CRITICAL_SECTIONS
79 /// Destructor. With debug-compilations, asserts that this lock is not acquired.
81 { Dbg.AssertNotOwned( ALIB_CALLER, ALIB_CALLER, "Destructing acquired lock" ); }
82
83 /// @return \c true if the lock is acquired (in non-shared mode), \c false otherwise.
84 ALIB_API virtual bool DCSIsAcquired() const override;
85
86 /// @return \c true if the lock is shared-acquired (by at least any thread).
87 /// Otherwise, returns \c false.
88 ALIB_API virtual bool DCSIsSharedAcquired() const override;
89 #elif ALIB_DEBUG
91 { Dbg.AssertNotOwned( ALIB_CALLER, ALIB_CALLER, "Destructing acquired lock" ); }
92 #endif
93
94 // ###############################################################################################
95 // Interface
96 // ###############################################################################################
97 public:
98
99 #if ALIB_DEBUG || DOXYGEN
100 //==============================================================================================
101 /// Thread which invokes this method gets registered as the current owner of this object,
102 /// until the same thread releases the ownership invoking #ReleaseRecursive.
103 /// In the case that this object is already owned by another thread, the invoking thread is
104 /// suspended until ownership can be gained.
105 /// Multiple (nested) calls to this method are counted and the object is only released when
106 /// the same number of Release() calls have been made.
107 ///
108 /// \par Debug Parameter:
109 /// Pass macro \ref ALIB_CALLER_PRUNED with invocations.
110 //==============================================================================================
113
114 /// Tries to acquire this lock.
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 /// \par Debug Parameter:
119 /// Pass macro \ref ALIB_CALLER_PRUNED with invocations.
120 ///
121 /// @return \c true if the lock was not acquired by a different thread and thus, this
122 /// call was successful. \c false otherwise.
124 [[nodiscard]]
126
127 /// A thread which invokes this method gets registered as the current owner of this object,
128 /// until the same thread releases the ownership invoking #ReleaseRecursive.
129 /// In the case that this object is already owned by another thread, the invoking thread is
130 /// suspended until ownership can be gained.<br>
131 /// Successful calls to this method are counted, as if #AcquireRecursive was called and an
132 /// according invocation of #ReleaseRecursive has to be performed.
133 ///
134 /// @param waitDuration The maximum time-span to wait.
135 /// @param ci Caller information.
136 /// Use macro \ref ALIB_COMMA_CALLER_PRUNED with invocations.
137 /// @return \c true if the lock was acquired, \c false if the \p{waitDuration} expired
138 /// without successful acquisition
140 [[nodiscard]]
141 bool TryAcquireTimed( const Ticks::Duration& waitDuration, const CallerInfo& ci );
142
143 /// Same as overloaded sibling, but expects a C++ standard library duration type
144 /// rather than an \b Ticks::Duration.
145 ///
146 /// @param waitDuration The point in time, when this method stops waiting.
147 /// @param ci Caller information.
148 /// Use macro \ref ALIB_COMMA_CALLER_PRUNED with invocations.
149 /// @return \c true if the lock was acquired, \c false if the \p{pointInTime} was reached
150 /// without successful acquisition.
151 [[nodiscard]]
152 bool TryAcquireTimed( const Ticks::Duration::TDuration& waitDuration, const CallerInfo& ci )
153 { return TryAcquireTimed( Ticks::Duration(waitDuration), ci); }
154
155 /// Same as overloaded sibling, but expects a point in time rather than an \b Ticks::Duration.
156 /// @param pointInTime The point in time, when this method stops waiting.
157 /// @param ci Caller information.
158 /// Use macro \ref ALIB_COMMA_CALLER_PRUNED with invocations.
159 /// @return \c true if the lock was acquired, \c false if the \p{pointInTime} was reached
160 /// without successful acquisition.
161 [[nodiscard]]
162 bool TryAcquireTimed( const Ticks& pointInTime, const CallerInfo& ci )
163 { return TryAcquireTimed( pointInTime - Ticks::Now(), ci); }
164
165 /// Same as overloaded sibling, but expects a C++ standard library point in time type
166 /// rather than an \b Ticks::Duration.
167 ///
168 /// @param pointInTime The point in time, when this method stops waiting.
169 /// @param ci Caller information.
170 /// Use macro \ref ALIB_COMMA_CALLER_PRUNED with invocations.
171 /// @return \c true if the lock was acquired, \c false if the \p{pointInTime} was reached
172 /// without successful acquisition.
173 [[nodiscard]]
174 bool TryAcquireTimed( const Ticks::TTimePoint& pointInTime, const CallerInfo& ci )
175 { return TryAcquireTimed( Ticks(pointInTime), ci); }
176
177 #else
178 void AcquireRecursive() { mutex.lock(); }
179 [[nodiscard]] bool TryAcquire() { return mutex.try_lock(); }
180 ALIB_API [[nodiscard]] bool TryAcquireTimed( const Ticks::Duration& waitDuration );
181 [[nodiscard]] bool TryAcquireTimed( const Ticks::Duration::TDuration& waitDuration ) { return TryAcquireTimed( Ticks::Duration(waitDuration) ); }
182 [[nodiscard]] bool TryAcquireTimed( const Ticks& pointInTime ) { return TryAcquireTimed( pointInTime - Ticks::Now() ); }
183 [[nodiscard]] bool TryAcquireTimed( const Ticks::TTimePoint& pointInTime ) { return TryAcquireTimed( Ticks(pointInTime) ); }
184 #endif
185
186 #if ALIB_DEBUG || DOXYGEN
187 /// Releases ownership of this object. If #AcquireRecursive was called multiple times before,
188 /// the same number of calls to this method has to be performed to release ownership.
189 /// \par Debug Parameter:
190 /// Pass macro \ref ALIB_CALLER_PRUNED with invocations.
193 #else
195 void ReleaseRecursive() { mutex.unlock(); }
196 #endif
197};
198
199
200} // namespace alib[::threads]
201
202/// Type alias in namespace \b alib.
204
205} // namespace [alib]
206
207#endif // HPP_ALIB_THREADS_RECURSIVETIMEDLOCK
208
virtual ALIB_API bool DCSIsAcquired() const override
Definition locks.cpp:280
ALIB_API bool TryAcquireTimed(const Ticks::Duration &waitDuration, const CallerInfo &ci)
Definition locks.cpp:613
DbgLockAsserter Dbg
The debug tool instance.
virtual ALIB_API bool DCSIsSharedAcquired() const override
Definition locks.cpp:281
bool TryAcquireTimed(const Ticks::TTimePoint &pointInTime, const CallerInfo &ci)
bool TryAcquireTimed(const Ticks::Duration::TDuration &waitDuration, const CallerInfo &ci)
ALIB_API void AcquireRecursive(ALIB_DBG_TAKE_CI)
Definition locks.cpp:561
ALIB_API void ReleaseRecursive(ALIB_DBG_TAKE_CI)
Definition locks.cpp:637
~RecursiveTimedLock() override
Destructor. With debug-compilations, asserts that this lock is not acquired.
ALIB_API bool TryAcquire(ALIB_DBG_TAKE_CI)
Definition locks.cpp:597
bool TryAcquireTimed(const Ticks &pointInTime, const CallerInfo &ci)
std::recursive_timed_mutex mutex
The internal object to lock on.
typename std::chrono::steady_clock::time_point TTimePoint
#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
threads::Thread Thread
Type alias in namespace alib.
Definition thread.hpp:379
time::Ticks Ticks
Type alias in namespace alib.
Definition ticks.hpp:115
void AssertNotOwned(const CallerInfo &assertCI, const CallerInfo &ci, const NString &headline)