I need to get a lock only during evaluation of the if
statement condition.
The lock must be released when running the code inside the if
or else
statements.
I found a piece of code and I don't know if it works. I'm rather new to C++, so please forgive me if this is an obvious question.
I found I cannot use this if
statement initializer:
if (std::lock_guard lock(mutex); condition) {
// do something
}
as it will be equivalent to the following, which will hold the lock also during execution of the if
or else
blocks:
{
std::lock_guard lock(mutex);
if (condition) {
// do something
}
}
I also found something like this:
if (std::lock_guard(mutex); condition) {
// do something
}
This will definitely not work. It will create the lock and then directly destroy it (and free the lock) as the lock_guard
is not stored in a variable.
So in fact, this example will not hold the lock when condition
is evaluated, and also not hold the lock during execution of the if
or else
blocks.
However, I also found this code:
if (std::lock_guard{mutex}, condition) {
// do something
}
Note that instead of a ;
there is a ,
and also the brackets differ, {}
instead of ()
.
This code compiles and run.
I verified that the lock is not held during execution of the if
or else
blocks, because the following does not dead-lock:
if (std::lock_guard{mutex}, condition) {
std::lock_guard lock(mutex);
// do something
}
Does the code in example 3 work as intended? That is, does it hold a lock during evaluation of condition
? I cannot find out if this line actually works. I'm afraid it may be similar to example 2.
Does this type of if
initializer have a name so I can read up on it?
What you found is not any special initialisation, it's the comma operator. Comma operator evaluates left hand side operand, discards it (although the object is not destroyed until end of expression), then evaluates right hand side and returns it. So std::lock_guard{mutex}, condition
creates temporary lock_guard
, ignores it, evaluates condition
and destroys temporary lock_guard
.
However, comma operator is a really obscure feature and it's hard to understand. It's also hard to notice, since comma is usually used in other contexts. I'd strongly recommend to simply extract a function
bool condition() {
std::lock_guard lock {mutex};
return /*evaluate the condition here*/;
}
and call it in if
:
if (condition()) {
// mutex isn't held here
} else {
// nor here
}
I verified that the lock is not held during execution of the if or else blocks because the following does not dead-lock:
if (std::lock_guard{mutex}, condition) { std::lock_guard lock(mutex); // do something }
If mutex
was locked here, you have Undefined Behaviour (because the thread that holds a lock on mutex attempts to lock it again), so this doesn't test anything.