Including std::lock_guard in extra scope
Yes, it certainly makes sense to limit the scope of lock guards to be as short as possible, but not shorter.
The longer you hold a lock, the more likely it is that a thread will block waiting for that lock, which impacts performance as is thus usually considered a bad thing.
However, you must make sure that the program is still correct and that the lock is held at all times when it must be, i.e. when the shared resource protected by the lock is accessed or modified.
There may be one more point to consider (I do not have enough practical experience here to speak with certainty). Locking/releasing a mutex can potentially be an operation with nontrivial performance costs itself. Therefore, it may turn out that keeping a lock for a slightly longer period instead of unlocking & re-locking it several times in the course of one operation can actually improve overall performace. This is something which profiling could show you.
There might be a disadvantage: you cannot protect initializations this way. For example:
{
std::lock_guard<std::mutex> lock(mut);
Some_resource var{shared_var};
} // oops! var is lost
you have to use assignment like this:
Some_resource var;
{
std::lock_guard<std::mutex> lock(mut);
var = shared_Var;
}
which may be suboptimal for some types, for which default initialization followed by assignment is less efficient than directly initializing. Moreover, in some situations, you cannot change the variable after initialization. (e.g. const
variables)
user32434999 pointed out this solution:
// use an immediately-invoked temporary lambda
Some_resource var {
[&] {
std::lock_guard<std::mutex> lock(mut);
return shared_var;
} () // parentheses for invoke
};
This way, you can protect the retrieval process, but the initialization itself is still not guarded.