BDE 4.14.0 Production release
|
Macros | |
#define | BSLMT_MUTEXASSERT_IS_LOCKED(mutex_p) ((void) 0) |
#define | BSLMT_MUTEXASSERT_IS_LOCKED_SAFE(mutex_p) ((void) 0) |
#define | BSLMT_MUTEXASSERT_IS_LOCKED_OPT(mutex_p) ((void) 0) |
Provide an assert macro for verifying that a mutex is locked.
This component provides macros for asserting that a mutex is locked. It does not distinguish between locks held by the current thread or other threads. If the macro is active in the current build mode, when the macro is called, if the supplied mutex is unlocked, the assert handler installed for BSLS_ASSERT
will be called. The assert handler installed by default will report an error and abort the task.
The three macros defined by the component are analogous to the macros defined by BSLS_ASSERT
:
BSLMT_MUTEXASSERT_IS_LOCKED
: active when BSLS_ASSERT
is activeBSLMT_MUTEXASSERT_IS_LOCKED_SAFE
: active when BSLS_ASSERT_SAFE
is activeBSLMT_MUTEXASSERT_IS_LOCKED_OPT
: active when BSLS_ASSERT_OPT
is activeIn build modes where any one of these macros is not active, calling it will have no effect.
If any of these asserts are in effect and fail (because the mutex in question was unlocked), the behavior parallels the behavior of the assertion macros defined in bsls_assert.h
– bsls::Assert::invokeHandler
is called, with a source code expression, the name of the source file, and the line number in the source file where the macro was called. If the default handler is installed, this will result in an error message and an abort.
This section illustrates intended use of this component.
Sometimes multithreaded code is written such that the author of a function requires that a caller has already acquired a mutex. The BSLMT_MUTEXASSERT_IS_LOCKED*
family of assertions allows the programmers to verify, using defensive programming techniques, that the mutex in question is indeed locked.
Suppose we have a fully thread-safe queue that contains int
values, and is guarded by an internal mutex. We can use BSLMT_MUTEXASSERT_IS_LOCKED_SAFE
to ensure (in appropriate build modes) that proper internal locking of the mutex is taking place.
First, we define the container:
Notice that our public manipulators have two forms: push/pop a single element, and push/pop a collection of elements. Popping even a single element is non-trivial, so we factor this operation into a non-*thread-safe* private manipulator that performs the pop, and is used in both public pop
methods. This private manipulator requires that the mutex be locked, but cannot lock the mutex itself, since the correctness of popAll
demands that all of the pops be collectively performed using a single mutex lock/unlock.
Then, we define the private manipulator:
Notice that, on the very first line, the private manipulator verifies, as a precondition check, that the mutex has been acquired, using one of the BSLMT_MUTEXASSERT_IS_LOCKED*
macros. We use the ...IS_LOCKED_SAFE...
version of the macro so that the check, which on some platforms is as expensive as locking the mutex, is performed in only the safe build mode.
Next, we define the public manipulators; each of which must acquire a lock on the mutex (note that there is a bug in popAll
):
Notice that, in popAll
, we forgot to lock/unlock the mutex!
Then, in our function example2Function
, we make use of our class to create and exercise a MyThreadSafeQueue
object:
Next, we populate the queue using pushRange
:
Then, we pop a few items off the front of the queue and verify their values:
Next, we attempt to empty the queue with popAll
, which, if built in safe mode, would fail because it neglects to lock the mutex:
Then, we build in non-safe mode and run:
Notice that, since the test case is being run in a single thread and our check is disabled, the bug where the mutex was not acquired does not manifest itself in a visible error, and we observe the seemingly correct output.
Now, we build in safe mode (which enables our check), run the program (which calls example2Function
), and observe that, when we call popAll
, the BSLMT_MUTEXASSERT_IS_LOCKED_SAFE(&d_mutex)
macro issues an error message and aborts:
Finally, note that the message printed above and the subsequent aborting of the program were the result of a call to bsls::Assert::invokeHandler
, which in this case was configured (by default) to call bsls::Assert::failAbort
. Other handlers may be installed that produce different results, but in all cases should prevent the program from proceeding normally.
#define BSLMT_MUTEXASSERT_IS_LOCKED | ( | mutex_p | ) | ((void) 0) |
#define BSLMT_MUTEXASSERT_IS_LOCKED_OPT | ( | mutex_p | ) | ((void) 0) |
#define BSLMT_MUTEXASSERT_IS_LOCKED_SAFE | ( | mutex_p | ) | ((void) 0) |