ALib C++ Library
Library Version: 2312 R0
Documentation generated by doxygen
Public Static Fields | Public Methods | Protected Fields | List of all members
SmartLock Class Reference

#include <smartlock.hpp>

Inheritance diagram for SmartLock:
[legend]
Collaboration diagram for SmartLock:
[legend]

Class Description


This class extends class ThreadLock, adding functionality to register 'acquirers' of type ThreadLock. Only with the second acquirer added, the lock is activated using method ThreadLock::SetSafeness. The goal is to not use a mutex, when such use is not needed. In occasions with very high frequency of acquisition, this can provide a performance benefit.

The following rules apply:

Using nulled acquirers:
Sometimes it is useful to add a nullptr as an acquirer. A sample for this is found and explained static field StdOutputStreams. If the first acquirer is nullptr, the second should be added in a thread-safe way. This means, the code invoking AddAcquirer needs to care for itself, that this object is not acquired during this process. E.g. it can be done in the bootstrap section of a process, when no parallel threads were started. For further acquirers, such care does not need to be taken. While an acquirer must not be attached twice, 'anonymous' (nullptr) acquirers may. For each anonymous invocation of AddAcquirer, a corresponding call RemoveAcquirer is needed, to get back to Safeness::Unsafe.

Definition at line 48 of file smartlock.hpp.

Public Static Fields

static ALIB_API SmartLock StdOutputStreams
 

Public Methods

 SmartLock ()
 
void Acquire (const NCString &dbgFile, int dbgLine, const NCString &dbgFunc)
 
ALIB_API int AddAcquirer (ThreadLock *newAcquirer)
 
ALIB_API int CntAcquirers ()
 
ALIB_API void Release ()
 defined(ALIB_DOX) More...
 
ALIB_API int RemoveAcquirer (ThreadLock *acquirer)
 
- Public Methods inherited from ThreadLock
ALIB_API ThreadLock (Safeness safeness=Safeness::Safe)
 
ALIB_API ~ThreadLock ()
 
ALIB_API void Acquire (const NCString &dbgFile, int dbgLine, const NCString &dbgFunc)
 
int CountAcquirements () const
 
ThreadGetOwner () const
 
Safeness GetSafeness () const
 
bool IsOwnedByCurrentThread () const
 
ALIB_API void Release ()
 defined(ALIB_DOX) More...
 
ALIB_API void SetSafeness (Safeness safeness)
 
bool WillRelease () const
 

Protected Fields

std::vector< ThreadLock * > acquirers
 
ThreadLockNR lock
 
- Protected Fields inherited from ThreadLock
uint16_t cntAcquirements =0
 
std::mutex mutex
 
std::condition_variable mutexNotifier
 
std::thread::id owner
 
Safeness safeness
 

Additional Inherited Members

- Public Fields inherited from ThreadLock
NCString DbgOwnerFile =nullptr
 
NCString DbgOwnerFunc =nullptr
 
int DbgOwnerLine
 
uint16_t DbgRecursionWarningThreshold =10
 
integer DbgWarningAfterWaitTimeInMillis =2000L
 

Constructor & Destructor Documentation

◆ SmartLock()

SmartLock ( )
inline

Constructs a SmartLock. Parent ThreadLock is initialized to Unsafe mode.

Definition at line 68 of file smartlock.hpp.

Member Function Documentation

◆ Acquire()

void Acquire ( const NCString dbgFile,
int  dbgLine,
const NCString dbgFunc 
)
inline

Overwriting ThreadLock::Acquire. With debug builds, asserts that at least one acquirer is set.

Note
In debug-compilations of the library, this method accepts three parameters, providing information about the caller. In the release version these parameters do not exist. Therefore use macro ALIB_CALLER_PRUNED to provide the parameters:
   sample.Acquire( ALIB_CALLER_PRUNED );
Parameters
dbgFileCaller information. Available only with debug builds.
dbgLineCaller information. Available only with debug builds.
dbgFuncCaller information. Available only with debug builds.

Definition at line 87 of file smartlock.hpp.

Here is the call graph for this function:

◆ AddAcquirer()

int AddAcquirer ( ThreadLock newAcquirer)

Adds an acquirer. With the second acquirer added, this lock will be set into safe mode.

Parameters
newAcquirerThe acquirer to add.
Returns
The new number of acquirers set.

Definition at line 29 of file smartlock.cpp.

Here is the call graph for this function:

◆ CntAcquirers()

int CntAcquirers ( )

Returns the number of acquirers. This is for debug and statistics purposes.

Returns
The number of acquirers set.

Definition at line 23 of file smartlock.cpp.

◆ Release()

void Release

defined(ALIB_DOX)


Releases ownership of this object. If Acquire was called multiple times before, the same number of calls to this method have to be performed to release ownership.

Definition at line 147 of file threadlock.cpp.

◆ RemoveAcquirer()

int RemoveAcquirer ( ThreadLock acquirer)

Removes an acquirer. If the amount of acquirers after removal equals 1, then this lock will be set to unsafe mode.

Parameters
acquirerThe acquirer to remove.
Returns
The new number of acquirers set.

Definition at line 92 of file smartlock.cpp.

Here is the call graph for this function:

Member Data Documentation

◆ acquirers

std::vector<ThreadLock*> acquirers
protected

The list of acquirers.

Definition at line 58 of file smartlock.hpp.

◆ lock

ThreadLockNR lock
protected

A lock for acquirer management.

Definition at line 55 of file smartlock.hpp.

◆ StdOutputStreams

SmartLock StdOutputStreams
static

This is a static singleton of this class that allows to lock an application's standard output streams.

In multi-threaded processes, to protect the output streams from concurrent access, this smart lock might be used by any entity that writes data to the streams. Before it can be used (acquired and released), it is needed to register with the object using SmartLock::AddAcquirer. This has to be done once per thread that aims to write to the stream. Then, prior to writing, this object has to be acquired and after writing released.

Because often, the standard output stream and standard error stream are identical, ALib provides one single lock for both, to protect also against interwoven standard output and error information.

If the 'entity' that is registering is not of type ThreadLock it is allowed to provide nullptr in the parameter of method AddAcquirer. In this case, the process of adding and removing acquirers is not performed in a thread safe way. Therefore it is advised to register so called anonymous (nullptr) acquirers only at bootstrap time, when no parallel threads were started, yet.

If an application is deemed to always write to the standard output streams from within multiple threads, an alternative to registering each writing entity, is to invoke AddAcquirer just two times in a row with nullptr at the start of a process and then never do this again (and never de-register). This way, no thread needs to register/de-register but threads may still Acquire and Release the lock without being registered. In other words, once a smart lock is enabled, subsequent registrations are just used to count and identify the de-registration.

Note
The advantage of the SmartLock is that if only one 'entity' registered, no system mutexes will be used with Acquire and Release, hence there is a performance gain. Such gain is not noticeable for the 'slow' terminal console output, but it is for fast, buffered output streams.
Logging module ALox, which is built on ALib, will register whenever a Logger is used that writes to the standard output stream. Hence, applications that in parallel use, e.g. 'std::cout', should register at bootstrap and acquire this instance prior to writing. This way, log output and other application output is not mixed, but separated in different Lines.

Definition at line 174 of file smartlock.hpp.


The documentation for this class was generated from the following files: