ALib C++ Library
Library Version: 2402 R1
Documentation generated by doxygen
Loading...
Searching...
No Matches
threadlocknr.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_THREADLOCKNR
9#define HPP_ALIB_THREADS_THREADLOCKNR 1
10
11#if !defined (HPP_ALIB_LANG_OWNER)
12 #include "alib/lang/owner.hpp"
13#endif
14
15ALIB_ASSERT_MODULE(THREADS)
16
17#if !defined (HPP_ALIB_STRINGS_LOCALSTRING)
19#endif
20
21#if !defined(HPP_ALIB_THREADS_THREAD)
23#endif
24
25
26#if !defined (_GLIBCXX_MUTEX) && !defined(_MUTEX_)
27 #include <mutex>
28#endif
29
30// #################################################################################################
31// Macros
32// #################################################################################################
33#define ALIB_LOCK ALIB_OWN(*this)
34#define ALIB_LOCK_WITH(lock) ALIB_OWN(lock)
35
36
37namespace alib { namespace threads {
38/** ************************************************************************************************
39 * This class is a simple wrapper around C++ standard library type \c std::mutex and hence allows
40 * <em>mutual exclusive access</em> to resources, by protecting data from concurrent thread access.
41 *
42 * When a pair of #Acquire and #Release invocations is performed within the same code block, then
43 * it is recommended to use a stack instantiation of class \alib{Owner} to acquire and release
44 * objects of this class. Such use is highly simplified with macros \ref ALIB_LOCK and
45 * \ref ALIB_LOCK_WITH.
46 *
47 * This class allows to be "disabled" with method #SetSafeness. The objective here is to
48 * gain execution speed, as thread synchronization causes "relatively" expensive system calls.
49 * An interface of a class might this way be designed to be "thread safe" by default, but in the
50 * case that a user of such class assures that an individual instance is used in a context that
51 * is free of race conditions, a corresponding lock might be disabled.
52 *
53 * This class does not allow repeated calls to method #Acquire without prior invocations of
54 * #Release. Repeated acquisitions cause undefined behavior.
55 * With debug builds, an assertion is raised when #Acquire is invoked while the lock is already
56 * acquired.
57 *
58 * Due to this limitation, the class performs several times faster than sibling class
59 * \alib{threads;ThreadLock}. For very time critical code sections which are invoked
60 * often in relation to their length, the use of this class might be considered, taking its
61 * limitation into account.
62 **************************************************************************************************/
64{
65 protected:
66 /** The std::mutex used for locking. */
67 typename std::mutex mutex;
68
69 /** The safeness mode. */
71
72 #if ALIB_DEBUG
73 /** Source location of acquirement. (Available only in debug-builds.). */
75
76 /** Source location of acquirement. (Available only in debug-builds.). */
78
79 /** Source location of acquirement. (Available only in debug-builds.). */
81
82
83 /** Id of a thread that currently acquired this object's mutex, used to detect forbidden
84 * multiple (nested) acquirements.Available only in debug compilations. */
85 std::thread::id dbgIsAcquiredBy;
86 #endif
87
88 public:
89 /** ****************************************************************************************
90 * Default constructor.
91 *
92 * @param pSafeness The safeness mode. See #SetSafeness for more information.
93 ******************************************************************************************/
94 explicit
96 : safeness( pSafeness )
97 {}
98
99 /** ****************************************************************************************
100 * A thread which invokes this method gets registered as the current owner of this object,
101 * until the same thread releases the ownership invoking #Release.
102 * In the case that this object is already owned by another thread, the invoking thread is
103 * suspended until ownership can be gained.
104 * Multiple (nested) calls to this method are not supported and lead to undefined behavior.
105 *
106 * \note
107 * In debug-compilations of the library, this method accepts three parameters,
108 * providing information about the caller. In the release version these parameters do not
109 * exist. Therefore use macro \ref ALIB_CALLER_PRUNED to provide the parameters:
110 *
111 * sample.Acquire( ALIB_CALLER_PRUNED );
112 *
113 * @param dbgFile Caller information. Available only with debug builds.
114 * @param dbgLine Caller information. Available only with debug builds.
115 * @param dbgFunc Caller information. Available only with debug builds.
116 ******************************************************************************************/
117 #if ALIB_DEBUG
118 void Acquire( const NCString& dbgFile, int dbgLine, const NCString& dbgFunc )
119 {
120 DbgOwnerFile= dbgFile;
121 DbgOwnerLine= dbgLine;
122 DbgOwnerFunc= dbgFunc;
123 #else
124 void Acquire()
125 {
126 #endif
127 ALIB_ASSERT_ERROR( dbgIsAcquiredBy != std::this_thread::get_id(), "THREADS",
128 "Multiple acquirements of ThreadLockNR are forbidden." )
129
131 mutex.lock();
132
133 ALIB_DBG( dbgIsAcquiredBy= std::this_thread::get_id(); )
134 }
135
136 /** ****************************************************************************************
137 * Releases ownership of this object.
138 * If this method is invoked on an object that is not acquired, in debug-compilations an
139 * assertion is raised. In release compilations, this leads to undefined behavior.
140 ******************************************************************************************/
141 void Release()
142 {
143 ALIB_ASSERT_ERROR( dbgIsAcquiredBy != std::thread::id() , "THREADS",
144 "Release without prior acquisition" )
145 ALIB_ASSERT_ERROR( dbgIsAcquiredBy == std::this_thread::get_id(), "THREADS",
146 NString256() <<
147 "Release while ownership is with a different thread.\n" <<
148 " This thread: " << Thread::GetCurrent()->GetName() << " (ID: "
149 << Thread::GetCurrent()->GetId() << ")\n"
150 " Owner: " << detail::getThread(dbgIsAcquiredBy)->GetName() << " (ID: "
151 << detail::getThread(dbgIsAcquiredBy)->GetId() << ")"
152 )
153 ALIB_DBG( dbgIsAcquiredBy= std::thread::id(); )
155 mutex.unlock();
156 }
157
158 /** ****************************************************************************************
159 * If parameter is \c Unsafe, the whole locking system is disabled.
160 * The only objective here is to gain execution speed, as thread synchronization causes
161 * relatively expensive system calls. Use this method only if you are 100% sure that your
162 * (otherwise) critical section is executed in a single threaded environment or otherwise
163 * it is assured that no concurrent thread access is performed.
164 *
165 * Note that "relative expensive" means: locking is not "really" expensive.
166 * This is only for the rare case that your critical section is very, very frequently
167 * executed.
168 *
169 * @param pSafeness Denotes the new safeness mode.
170 ******************************************************************************************/
171 void SetSafeness( lang::Safeness pSafeness )
172 {
173 ALIB_ASSERT_ERROR( dbgIsAcquiredBy != std::thread::id()
174 && dbgIsAcquiredBy != std::this_thread::get_id(), "THREADS",
175 NString256() <<
176 "Changing safeness while acquired by a different thread.\n" <<
177 " This thread: " << Thread::GetCurrent()->GetName() << " (ID: "
178 << Thread::GetCurrent()->GetId() << ")\n"
179 " Owner: " << detail::getThread(dbgIsAcquiredBy)->GetName() << " (ID: "
180 << detail::getThread(dbgIsAcquiredBy)->GetId() << ")"
181 )
182 ALIB_ASSERT_ERROR( dbgIsAcquiredBy == std::thread::id() , "THREADS",
183 "Changing safeness while acquired (by this thread)." )
184 ALIB_DBG( dbgIsAcquiredBy= std::thread::id(); )
185 safeness= pSafeness;
186 }
187
188 /** ****************************************************************************************
189 * Query the safeness mode of this object.
190 * @return The safeness mode of this object.
191 ******************************************************************************************/
193 {
194 return safeness;
195 }
196};
197
198
199} // namespace alib[::threads]
200
201/// Type alias in namespace \b alib.
203
204} // namespace [alib]
205
206#endif // HPP_ALIB_THREADS_THREADLOCKNR
void SetSafeness(lang::Safeness pSafeness)
void Acquire(const NCString &dbgFile, int dbgLine, const NCString &dbgFunc)
lang::Safeness GetSafeness() const
ThreadLockNR(lang::Safeness pSafeness=lang::Safeness::Safe)
std::thread::id dbgIsAcquiredBy
static Thread * GetCurrent()
Definition thread.hpp:288
#define ALIB_ASSERT_MODULE(modulename)
Definition alib.hpp:190
#define ALIB_ASSERT_ERROR(cond,...)
Definition alib.hpp:984
#define ALIB_DBG(...)
Definition alib.hpp:457
@ Safe
Do it or treat it with safety.
ALIB_API Thread * getThread(std::thread::id c11ID)
Definition thread.cpp:96
Definition alib.cpp:57
NLocalString< 256 > NString256
Type alias name for TLocalString<nchar,256> .