This class supports detecting a racing condition in multithreaded applications. For this, entering and exiting of critical sections is tracked in either "write" or "read only" mode. The interface methods are named in accordance with types Owner (Acquire/Release) and OwnerShared (AcquireShared/ReleaseShared).
With the use of atomic counters, both pairs of acquirement are reentrant, which simplifies the use of this type. Furthermore, it is allowed to gain read access after write access by the same thread was acquired. The reverse is not allowed: If the first read access was registered, a subsequent write access will be asserted.
The type becomes empty, and thus any call will be optimized out in case the compiler symbol ALIB_DEBUG_CRITICAL_SECTIONS is not set. Nevertheless, it is recommended to exclusively use the ALib Module Threads Macros when using this type, as those fully guarantee that any use of this type is pruned with release compilations. Only in exclamatory cases, these macros may not be flexible enough for use.
In case critical sections that are protected using this class are in fact protected by one of the ALib mutex types, it can furthermore be asserted that such mutex is acquired when a section is entered. For this, assign the instance to field DCSLock. A lock-instance may be assigned to more than one DbgCriticalSections instance.
If the compiler symbol ALIB_DEBUG_CRITICAL_SECTIONS is set, besides counting owners and readers, and raising corresponding assertions, the type can be enabled to simulate some workload on the using machine. For this, a thread can be forced to either yield to the system or even to sleep a given number of nanoseconds before continuing execution. This increases the probability of (detecting) racing conditions.
To activate this feature for all instances, namespace variable DBG_CRITICAL_SECTION_YIELD_OR_SLEEP_TIME_IN_NS is to be adjusted. Per-instance adjustments can be made by setting the field DCSYieldOrSleepTimeInNS.
The output format of assertions should be 'clickable' inside a users' IDE. The default output string is optimized for JetBrains CLion and can be changed by manipulating the member ASSERTION_FORMAT.
Definition at line 112 of file dbgcriticalsections.hpp.
#include <dbgcriticalsections.hpp>
Inner Type Index: | |
struct | AssociatedLock |
Public Static Field Index: | |
static ALIB_API const char * | ASSERTION_FORMAT |
Public Field Index: | |
CallerInfo | DCSAcq |
Source location of acquirement. | |
AssociatedLock * | DCSLock {nullptr} |
const char * | DCSName |
The name of this DCS. Used for debug-output. | |
std::atomic< int > | DCSReaderCnt {0} |
Tracks enter/exit calls of readers. | |
CallerInfo | DCSRel |
Source location of the last "reader" seen. | |
CallerInfo | DCSSAcq |
Source location of acquirement. | |
CallerInfo | DCSSRel |
Source location of the last "reader" seen. | |
std::atomic< int > | DCSWriterCnt {0} |
Tracks enter/exit calls (including readers) | |
int | DCSYieldOrSleepTimeInNS = -1 |
Public Method Index: | |
ALIB_FORCE_INLINE | DbgCriticalSections (const char *name) |
ALIB_FORCE_INLINE | ~DbgCriticalSections () |
Destructor. Checks that this instance is unused. | |
ALIB_API void | Acquire (const CallerInfo &ci) const |
ALIB_API void | AcquireShared (const CallerInfo &ci) const |
ALIB_API void | doAssert (bool cond, const CallerInfo &ciAssert, const CallerInfo &ci, const char *headline) const |
ALIB_API void | Release (const CallerInfo &ci) const |
ALIB_API void | ReleaseShared (const CallerInfo &ci) const |
ALIB_FORCE_INLINE void | yieldOrSleep () const |
|
static |
The format string used to write exceptions to the console. This string can be changed if the source information is not "clickable" in a user's development environment.
The default string is optimized for JetBrains CLion and is defined as:
Assertion in Critical Section {!Q} Message: {} In (Member-)Function: {2:ya} Is Owned: {6} Is Shared Owned: {9} Called By: {3:ya} At: {3:sf:sl} Thread: {3:ta} Latest Acquisition By: {4:ya} At: {4:sf:sl} Thread: {4:ta} Latest Release By: {5:ya} At: {5:sf:sl} Thread: {5:ta} Latest Shared Acquisition By: {7:ya} At: {7:sf:sl} Thread: {7:ta} Latest SharedRelease By: {8:ya} At: {8:sf:sl} Thread: {8:ta}
The placeholder fields that this format string refers to are set as follows:
0
: Debug-name of the critical section.1
: Headline.2
: CallerInfo of assertion.3
: CallerInfo of caller.4
: CallerInfo of latest acquisition.5
: CallerInfo of latest release.6
: Acquirement information string7
: CallerInfo of latest shared acquisition.8
: CallerInfo of latest shared release.9
: Shared acquirement information string.The format specification of the type CallerInfo
is defined with class FMTCallerInfo.
Definition at line 204 of file dbgcriticalsections.hpp.
|
mutable |
Source location of acquirement.
Definition at line 144 of file dbgcriticalsections.hpp.
AssociatedLock* DCSLock {nullptr} |
A union of pointers to different lock types. Those can optionally be attached to be checked whether a lock is duly acquired.
Definition at line 151 of file dbgcriticalsections.hpp.
const char* DCSName |
The name of this DCS. Used for debug-output.
Definition at line 135 of file dbgcriticalsections.hpp.
|
mutable |
Tracks enter/exit calls of readers.
Definition at line 143 of file dbgcriticalsections.hpp.
|
mutable |
Source location of the last "reader" seen.
Definition at line 145 of file dbgcriticalsections.hpp.
|
mutable |
Source location of acquirement.
Definition at line 146 of file dbgcriticalsections.hpp.
|
mutable |
Source location of the last "reader" seen.
Definition at line 147 of file dbgcriticalsections.hpp.
|
mutable |
Tracks enter/exit calls (including readers)
Definition at line 142 of file dbgcriticalsections.hpp.
int DCSYieldOrSleepTimeInNS = -1 |
If positive, the value found here, overwrites what is given with namespace variable DBG_CRITICAL_SECTION_YIELD_OR_SLEEP_TIME_IN_NS.
Defaults to -1
.
Definition at line 140 of file dbgcriticalsections.hpp.
|
inline |
Constructor.
name | The name to display with assertions. |
Definition at line 242 of file dbgcriticalsections.hpp.
|
inline |
Destructor. Checks that this instance is unused.
Definition at line 245 of file dbgcriticalsections.hpp.
void Acquire | ( | const CallerInfo & | ci | ) | const |
Increases the DCSWriterCnt and checks for potential assertions.
ci | Caller information. |
Definition at line 111 of file dbgcriticalsections.cpp.
void AcquireShared | ( | const CallerInfo & | ci | ) | const |
Increases DCSReaderCnt and checks for potential assertions.
ci | Caller information. |
Definition at line 132 of file dbgcriticalsections.cpp.
void doAssert | ( | bool | cond, |
const CallerInfo & | ciAssert, | ||
const CallerInfo & | ci, | ||
const char * | headline ) const |
Raises an ALib assertion.
cond | The condition to assert. |
ciAssert | Caller information of the assertion in this class. |
ci | Caller information. |
headline | The problem that occurred. |
Definition at line 62 of file dbgcriticalsections.cpp.
void Release | ( | const CallerInfo & | ci | ) | const |
Decreases the DCSWriterCnt and checks for potential assertions.
ci | Caller information. |
Definition at line 123 of file dbgcriticalsections.cpp.
void ReleaseShared | ( | const CallerInfo & | ci | ) | const |
Decreases DCSReaderCnt and checks for potential assertions.
ci | Caller information. |
Definition at line 145 of file dbgcriticalsections.cpp.
|
inline |
Evaluates DCSYieldOrSleepTimeInNS, respectively, if this is negative, DBG_CRITICAL_SECTION_YIELD_OR_SLEEP_TIME_IN_NS. For value
0
, nothing is done, for1
, a yield into the system is done, and for1
, the calling thread sleeps for the corresponding number of nanoseconds sleep time. Definition at line 218 of file dbgcriticalsections.hpp.